microsoft / microsoft/TypeScript
Computed property key names should not be widened
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
TypeScript Version: 2.1.5
Code
The latest @types/react (v15.0.6) use Pick<S,K> to correctly type the setState method of React.Components. While this makes it now possible to merge the state of a component instead of replacing it, it also makes it harder to write a dynamic update function that uses computed properties.
import * as React from 'react';
interface Person {
name: string;
age: number|undefined;
}
export default class PersonComponent extends React.Component<void, Person> {
constructor(props:any) {
super(props);
this.state = {
name: '',
age: undefined
};
this.handleUpdate = this.handleUpdate.bind(this);
}
handleUpdate (e:React.SyntheticEvent<HTMLInputElement>) {
const key = e.currentTarget.name as keyof Person;
const value = e.currentTarget.value;
this.setState({ [key]: value }); // <-- Error
}
render() {
return (
<form>
<input type="text" name="name" value={this.state.name} onChange={this.handleUpdate} />
<input type="text" name="age" value={this.state.age} onChange={this.handleUpdate} />
</form>
);
}
}
The above should show an actual use case of the issue, but it can be reduced to:
const key = 'name';
const value = 'Bob';
const o:Pick<Person, 'name'|'age'> = { [key]: value };
which will result in the same error. Link to the TS playground
Expected behavior:
No error, because key is a keyof Person, which will result in the literal type "name" | "age". Both values that are valid keys forstate.
Actual behavior:
The compiler will throw the following error:
[ts] Argument of type '{ [x: string]: string; }' is not assignable
to parameter of type 'Pick<Person, "name" | "age">'.
Property 'name' is missing in type '{ [x: string]: string; }'.
My uninformed guess is that the constant key is (incorrectly) widened to string.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the reduced reproduction in the issue or the linked TypeScript playground, then trace how computed property names are inferred and widened. Compare the result with the expected keyof Person behavior and the React setState example. Done means both reproductions type-check without losing the literal key union.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100