- Notifications
You must be signed in to change notification settings - Fork 13k
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.Component
s. 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
.