Accepted answer


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:

    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!


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)
More accurate typing of Object.assign and React component setState()


I don't like casting and workarounds that gives you a lot place to make a mistake while you're scaling your project. Here'is my solution.

  1. We have to get proper intellisense for key by using generic type

<K extends keyof MainState>

  1. Then, we have to get proper type for value based on entered key

typeof MainState[K]

  1. In order to get code without and an error and without using casting/workarounds etc, pass callback into this.setState

  2. Combining all together

onChange = <K extends keyof MainState>(fieldName: K, value: typeof MainState[K]) => {
        this.setState((prevState) => {
            return {
                [fieldName]: value,


Edit: DO NOT USE this solution, prefer See comments for details.

Now that spread operator has shipped in TS, my preferred solution is

this.setState({...this.state, editorState}); // do not use !


We can tell setState which field it should expect, by parametrising it with <'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:

  [key]: value,

and as mentioned above, it doesn't complain if we pass an extra field.

(GitHub issue)


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.


Update state explicitly, example with the counter

this.setState((current) => ({ ...current, counter: current.counter + 1 }))

Related Query

More Query from same tag