Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using react-router in react ES6 component with Typescript #5406

Closed
roboto84 opened this issue Aug 17, 2015 · 9 comments
Closed

Using react-router in react ES6 component with Typescript #5406

roboto84 opened this issue Aug 17, 2015 · 9 comments

Comments

@roboto84
Copy link

Basically, I can not find a way to make Typescript understand react-router's new way of using the context in react ES6 components. Mainly, using code like this to get the react-router to function in react ES6 classes:

import React from 'react';
class LoginPage extends React.Component {
  ...
  onChange() {
    this.context.router.replaceWith('/');
  }
  ...
}

LoginPage.contextTypes = {
  router: React.PropTypes.func.isRequired
};

export default LoginPage;

Gives an error like this: Property 'contextTypes' does not exist on type 'typeof LoginPage'.

Every React component using ES6 and react-router will need to do this since react's new ES6 features does not support mixins. I am linking the discussion of this issue from the react-router repo (remix-run/react-router#975). Has anyone seen this before? How are people using Typescript, React ES6 components, and react-router?

Is this an issue with the react-router type definitions? react type definitions? none of the above? I'm not sure.

@roboto84
Copy link
Author

After 3hrs, solved it with ES7 syntax:

import React from 'react';
class LoginPage extends React.Component {

  static contextTypes = {
  router: React.PropTypes.func.isRequired
};

...
  onChange() {
    this.context.router.replaceWith('/');
  }
  ...
}

export default LoginPage;

@roboto84
Copy link
Author

Ok, still not solved, as now Typescript is complaining about this syntax (the new way react-router is used in ES6 react classes). I'm getting the following TS error now, but this is the only way to use react-router in react ES6 classes:

(51,19): Type 'typeof Unauthorized' is not assignable to type 'ComponentClass<any>'.
  Types of property 'contextTypes' are incompatible.
    Type '{ router: Validator<any>; }' is not assignable to type 'ValidationMap<any>'.
      Index signature is missing in type '{ router: Validator<any>; }'.

Narrowed down the culprit to the React TS def. file at:

interface ComponentClass<P> {
        new(props?: P, context?: any): Component<P, any>;
        propTypes?: ValidationMap<P>;
        contextTypes?: ValidationMap<any>;
        childContextTypes?: ValidationMap<any>;
        defaultProps?: P;
    }

Commenting out contextTypes?: ValidationMap<any>; makes it work, but I am nervous of the repercussions. Has anyone else seen this, or is everyone still using React without ES6? Heading over to the TS React definition section, as this is obviously an issue for them, not the React-Router def. Although interestingly enough, the React def. file has implications on whether you can use react-router or not.

@roboto84
Copy link
Author

Ok, just figured out that TS wanted contextTypes typed, here is the final version for anyone else that may run into this. Not an issue with the react, or react rout-er type definitions:

import React from 'react';
class LoginPage extends React.Component {

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

...
  onChange() {
    this.context.router.replaceWith('/');
  }
  ...
}

Hopes that helps any other poor souls trying to use react-router with react ES6 classes in typescript.

@flq
Copy link

flq commented Aug 20, 2015

Thanks to you and to Marius Rumpf for making me realize that said contextTypes must be a static property, awesome, don't know what I would do without all of you people who document your findings!

@Dindaleon
Copy link

Great! thanks Mauricio, is this documented somewhere? If not, it should!!

@nojaf
Copy link
Contributor

nojaf commented Sep 14, 2015

Thanks, this helped me as well!

@danielbanfield
Copy link

This was very helpful for me too thanks! :)

A couple of other notes in case it's helpful to others stumbling here to do programmatic react-router redirection as I was. afaict react-router no longer injects 'router'
https://github.com/rackt/react-router/search?utf8=%E2%9C%93&q=childContextTypes&type=Code

I instead used history, and also for whatever reason needed to cast the context as 'any' since context.history was flagged as not existing

static contextTypes: React.ValidationMap<any> = {
  history: React.PropTypes.object.isRequired
};
...
(this.context as any).history.pushState(null, '/');

@ppoliani
Copy link

@danielbanfield it was flagged as not existing because the type of context is context: {}; which means history is not available on an empty object.

Ideally it would be nice to change the definition of Component to something like this:

class Component<P, S, C> implements ComponentLifecycle<P, S, C> {
    ...
    context: C
}

It's easy then to pass a custom context type.

@farfromrefug
Copy link

@ppoliani love your idea!
This will be very easy when typescript supports generic type variables microsoft/TypeScript#2175

manrueda added a commit to manrueda/electro-dojo that referenced this issue Jun 24, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants