ts-migrate adding `setState: any` type declaration to react component classes, causing compilation problem
After a ts-migrate on my project, I observed react classes with setState: any would compile to have this.setState = void 0; in their constructor, leaving you with "TypeError: this.setState is not a function` errors
It looks like this can happen if the React types package (@types/react) is not installed when the migration runs. In this case, ts-migrate cannot tell that setState comes from the base class, so the declare-missing-class-properties plugin adds a declaration.
It might be nice if ts-migrate could install @types packages for dependencies that don't have their own types, prior to running any other migration.
I'm surprised that this.setState = void 0; is included in the compiled output, though. Could you please share what your compilation process is? Do you compile TypeScript using the TypeScript compiler or Babel, and what version do you use? I have tried some simple cases with both the TypeScript playground and Babel repl, but I can't convince either of them to emit this.setState = undefined; or this.setState = void 0; by including setState: any as a class member.
I wonder if classes that inherit from a base class with unknown types should use ! in their type declarations to assert that the property is initialized. Possibly that would prevent this initialization? I need to be able to reproduce the problem first though.
this was on a ~50 or so component project using create-react-app originally targetting js . a lot has moved in the month so not sure if I can give accurate repro steps unfortunately
in particular i cant remember if i went through the ts-migrate process before rerunning create-react-app and targetting typescript
Thanks, I think I have an idea of what could cause this issue.
If you specify useDefineForClassFields in tsconfig.json, then the compiler will define each property using Object.defineProperty, which initializes it to undefined. (Example) I still can't convince the Babel repl to do it, but I'm sure there's some way as I believe that the TC39 proposal basically requires it.
It looks like even including ! does not change the way TypeScript emits the code.
The only kinda decent fix for this that I can see is adding an index signature when we encounter this case:
class Component extends React.Component {
[k: string]: any;
// ...
}
In the above case it's pretty avoidable if you install @types/react, but there may not always be types available.