allow typescript compiler to call setState on only one react state property
I think that the best way to do it is to use Partial
Declare your component in the following way
class Main extends React.Component<MainProps, Partial<MainState>> {
}
Partial automatically changes all of the keys to optional.
Edit
The definitions for react were updated and the signature for setState
are now:
setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;
Where Pick<S, K>
is a built-in type which was added in Typescript 2.1:
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
}
See Mapped Types for more info.
If you still have this error then you might want to consider updating your react definitions.
Original answer:
I'm facing the same thing.
The two ways I manage to get around this annoying issue are:
(1) casting/assertion:
this.setState({
editorState: editorState
} as MainState);
(2) declaring the interface fields as optional:
interface MainState {
todos?: Todo[];
hungry?: Boolean;
editorState?: EditorState;
}
If anyone has a better solution I'd be happy to know!
Edit
While this is still an issue, there are two discussions on new features that will solve this problem:
Partial Types (Optionalized Properties for Existing Types)
and
More accurate typing of Object.assign and React component setState()
We can tell setState
which field it should expect, by parametrising it with <'editorState'>
:
this.setState<'editorState'>({
editorState: editorState
});
If you are updating multiple fields, you can specify them like this:
this.setState<'editorState' | 'hungry'>({
editorState: editorState,
hungry: true,
});
although it will actually let you get away with specifying only one of them!
Anyway with the latest TS and @types/react
both of the above are optional, but they lead us to...
If you want to use a dynamic key, then we can tell setState
to expect no fields in particular:
this.setState<never>({
[key]: value,
});
and as mentioned above, it doesn't complain if we pass an extra field.
(GitHub issue)
Update state explicitly, example with the counter
this.setState((current) => ({ ...current, counter: current.counter + 1 }))