No examples for this.
The React.Component
class contains no field for contextTypes
either.
It is unclear how to use it from within TypeScript and also how those types will be made available inside the component.
It would be great if the first code example here was converted to Typescript to show as a guide to users
http://jaysoo.ca/2015/06/09/react-contexts-and-dependency-injection/
Check out this example:
import * as React from 'react';
interface IRouter {
replaceWith(path: string);
}
interface IRouterContext {
router: IRouter;
}
interface ISomeOtherContext {
somethingElse: any;
}
export class MyComponent extends React.Component<any, any> {
context: IRouterContext & ISomeOtherContext;
static contextTypes = {
router: React.PropTypes.func.isRequired
}
onClick = () => {
this.context.router.replaceWith('/');
}
render() {
return <div onClick={this.onClick} />
}
}
There are two things going on here that are interesting. First is static contextTypes
which answers your first question. The second is context: IRouterContext & ISomeOtherContext;
which allows you to type this.context
correctly. In this case I'm just showing a quick example of how you can use intersection types to combine multiple distinct interfaces.
TypeScript doesn't actually _need_ to know about contextTypes
from a typing perspective (that's really more of a runtime concern) so how I personally do it is with decorators.
import { Router, IRouterContext } from './myRouter';
@Router
export class MyComponent extends React.Component<any, any> {
context: IRouterContext;
onClick = () => {
this.context.router.replaceWith('/');
}
render() {
return <div onClick={this.onClick} />
}
}
Where Router
is a decorator function that dynamically adds the contextTypes.
@jbrantly can you share the code or the Router
decorator?
Nope. That's a highly guarded, proprietary, confidential secret. Ah what the hell.
import * as ReactRouter from 'react-router';
import React from 'react';
export function Router(target: any) {
target.contextTypes = target.contextTypes || {};
target.contextTypes.router = React.PropTypes.func.isRequired;
}
export interface IRouterContext {
router: ReactRouter.Router;
}
In the future questions of this sort might be better for StackOverflow unless you think there's an actual TypeScript bug/issue (or if for example you wanted some examples in our handbook/wiki).
Just to complete the answer about using contexts with typescript (furthermore it would be more generally be valuable to have more explanations about the whole jsx/react stuff in typescript doc, e.g. contexts use, props and state use, ....), we need to add information in the containing components AND in the subcomponents :+1:
In the containing component , something like that :
static childContextTypes= {
open: React.PropTypes.func.isRequired
}
getChildContext() {
return {open: (value)=>this.changeState("",value)}
}
and in the subcomponent :
export interface SectionContext {
open : (string)=>void;
}
export class Section extends React.Component<SectionProps,{}> {
isOpen =false;
context: SectionContext; // context object typed with the context interface
// registration of the context type, already defined into the containing component
static contextTypes = {
open: React.PropTypes.func.isRequired
}
change() {
this.isOpen = !this.isOpen;
// use of the context described in the containing component
this.context.open(this.isOpen?"true":"false");
}
When I attempt to use React.PropTypes, I always get the following error back in the console:
(26,21): error TS2305: Module '__React' has no exported member 'PropTypes'.
@christhomas me too. You're not alone. I'm surprised no one else is suffering this issue. I'm using the ambient typings for React.
Are you two using an up to date react.d.ts
? Because it seems to be there? If you have a project that repros that you could send over, that would be good to check out.
@DanielRosenwasser Yes, I've looked at it myself.
I found a resolution (I was doing things wrong) but I still think it's rather odd that the compiler throws this error. It's probably most helpful to demonstrate what works and what doesn't with my IDE highlighting.
src/containers/LoginPage.tsx (17,20): Module '__React' has no exported member 'PropTypes'. (2305)
L14 & L17 are the lines of interest.
Now, I screwed up with L16-18 - I guess TS thinks this is a type, but still, why can't the compiler see PropTypes on React when L14 can? It leads to a lot of confusion.
Yes! this is actually working for me too @lukebarton, when you write it as the top line L14, then it does indeed work and now everything is picking it up as expected.
@lukebarton the static property works for me but when I add line 16-18, I get
error TS2305: Module '__React' has no exported member 'PropTypes'.
Did you run into that?
@zachariahtimothy I fixed this, http://stackoverflow.com/questions/38393797/how-to-reuse-type-definition-in-childcontexttypes-in-react
But, I have to rewrite the same type definition
@rogerdehe @zachariahtimothy this new typescript feature might help with the rewrite same type definition: https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#mapped-types
@OzBob how can it help, if interface is a compile-time feature, while the problem we have here is the need for prop types at run-time? No, an interface alone won't solve this problem because an interface is totally non existent during run-time.
I've been struggling with contextType and with React 16.2.0 I found this solution:
import * as React from 'react'
import * as PropTypes from 'prop-types';
interface ProviderChildContext {
blah: string;
}
export class Provider extends React.Component<void, void>
implements React.ChildContextProvider<ProviderChildContext> {
static childContextTypes = {
blah: PropTypes.string
};
getChildContext() {
return {
blah: 'foo'
};
}
}
...pasting it here as this was the most relevant thread when searching through google :)
Most helpful comment
Nope. That's a highly guarded, proprietary, confidential secret. Ah what the hell.