16
votes

I am using the Microsoft TypeScript-React-Starter and got this compile error during npm start:

./src/index.tsx
(16,5): error TS2605: JSX element type 'App' is not a constructor function for JSX elements.
  Types of property 'setState' are incompatible.
    Type '{ <K extends never>(f: (prevState: null, props: {}) => Pick<null, K>, callback?: (() => any) | un...' is not assignable to type '{ <K extends never>(f: (prevState: {}, props: any) => Pick<{}, K>, callback?: (() => any) | undef...'.
      Types of parameters 'f' and 'f' are incompatible.
        Type '(prevState: {}, props: any) => Pick<{}, any>' is not assignable to type '(prevState: null, props: {}) => Pick<null, any>'.
          Types of parameters 'prevState' and 'prevState' are incompatible.
            Type 'null' is not assignable to type '{}'.

So it seems like my setState function has incorrect signature but I'm not sure how to fix it. Here's my code:

class App extends React.Component<{}, null> {
  render() {
    return (
      <div className="App">
        ...
      </div>
    );
  }
}

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root') as HTMLElement
);

I am using:

node v6.11.0
npm v5.1.0
typescript v2.4.1
react v15.6.1
redux v3.7.1
react-redux v5.0.5
react-scripts-ts v2.3.2

Update:

I found out that removing the generic types <{}, null> clears the error. But I'd still love to learn why I was getting the error.

2
If App component does not use state, you can actually make it a functional stateless component instead.Mμ.
@D-reaper App does use state in my case. I'm using redux to manage the state. I guess that's why I don't have to explicitly write prevState()?Zening Qu
I think since you are passing null as the second type argument in React.Component, which defines the structure of state and that it is only compatible with certain types (e.g object) thus causing TS to throw that error. <any, any> or just <{}> would also work.Mμ.

2 Answers

20
votes

TLDR; State cannot be null. Declare a interface for it or declare it {}

Answer lies in @types/react

Looking at the definition, neither state nor props are not intended to be null.

When you declared App as class App extends React.Component<{}, null> {, you essentially said, "state is of type null".

Now the type of setState is dependent on the type you specify for state and it clashed with the lesser known version of the setState api. prevState is declared as a {} (the default, since no interface for state was specified) which is not compatible with null, leading to the error log you saw.

2
votes

Maybe this fix isn't relevant but I got the same error message without having <{}, null> after class App extends React.Component. Here is the fix in my case.

Change import React from 'react';

to import * as React from 'react';