Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to define a React component's contextTypes in TypeScript?

How does one define the contextTypes in TypeScript?

I have a component (note: I'm unsure of the necessary type of router as detailed in this question but that should be irrelevant here)

export class Repos extends React.Component<ReposProps, {}> {
    context: {
        router: History
    }

    static contextTypes = {
        router: React.PropTypes.object
    };

It has a function

    public handleSubmit(event: React.FormEvent) {

at the end of that function, it calls on context

        this.context.router.push(path);
    }

The component has a form

    public render() {
        return (
            {/* ... */}
                <form onSubmit={this.handleSubmit}>
        );
    }
}

However, on the line with this.context.router.push(path); I receive the error "Uncaught TypeError: Cannot read property 'router' of undefined" When compiling this same code, I received the TypeScript error in the file that uses Repos in a Router:

ERROR in ./index.tsx
(14,34): error TS2322: Type 'typeof Repos' is not assignable to type 'string | ComponentClass<any> | StatelessComponent<
any>'.
  Type 'typeof Repos' is not assignable to type 'StatelessComponent<any>'.
    Types of property 'contextTypes' are incompatible.
      Type '{ router: Requireable<any>; }' is not assignable to type 'ValidationMap<any>'.

Changing the contextTypes to

static contextTypes: React.ValidationMap<any> = {
    router: React.PropTypes.object
};

fixed the TypeScript error, although I doubt it was necessary; I suspect a different problem that is the cause of both of these issues.

According to discussions in TypeScript issue 4785: How to use React contextTypes in Typescript 1.6?, the code above is correct. If it helps, I'm using TypeScript 1.7.3, React 0.14.7 and react-router 2.0.0.

like image 570
mejdev Avatar asked Feb 21 '16 21:02

mejdev


1 Answers

We've all seen this problem at one time or another in our careers. It's surprising that I didn't catch this.

The problem is that the context of this in handleSubmit() is different because of how handleSubmit is called. Changing handleSubmit into a fat arrow definition works:

public handleSubmit = (event: React.FormEvent) => {

In this particular case, I overlooked that because I don't run into this problem often in the TypeScript world (I also don't work with DOM elements often, and have been with React for under a week... no excuses, I know)

like image 174
mejdev Avatar answered Oct 26 '22 18:10

mejdev