Definitelytyped: React 0.13 Context

Created on 12 Feb 2015  路  19Comments  路  Source: DefinitelyTyped/DefinitelyTyped

There is some concern from #3615 about whether Context is a valid type parameter for the React component. The argument is that it is confusing and provides little. My approach is that Context is as valid as Props and State and should be represented. It can easily be ignored by

class ContextlessComponent extends React.Component<Props, State, any> {
}

cc @fdecampredon

Most helpful comment

Referencing recent react typing contributors to get their input.
@tkrotoff @morcerf @sandersn @minestarks @mhegazy @dyst5422 @andy-ms @apexskier @yuit @janechu @p-jackson @ddwwcruz @DovydasNavickas @ericanderson

I was interested in seeing if anyone in the community felt that adding the 3rd generic parameter for context type back into the typings would be an acceptable feature now that typescript supports generic parameter defaults as of version 2.3.

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-3.html#generic-parameter-defaults

The third generic parameter for context could be defaulted as TContext = any. This would allow existing usage with just to continue as is while also providing the ability to directly specify the context type for those who wish to make use of it.

All 19 comments

Like I said I think that context being an undocumented features and used by very few user does not deserve to be part of the React signature, we can for example use a definition like that :

class Component<P,S> {
   context: any
}

those who wants to subclass Component and use the context just would have to do:

class MyClass extends React.Component<{},{}> {
  context: { myContextVar: string}
}

That's especially not a problem since anyway there is no way to enforce type checking on the context related generic (you never use it in signature when you instantiate your react component)

yeah, in type terms context is an _associated type_ rather than a _generic parameter_ here. .d.ts should follow documented usage of a library, not its implementation

@gulbanana Just so I'm on the same page, when you say _associated type_ do you mean something like abstract type members in Scala/associated types in Swift? If so, that's essentially the same thing as a generic parameter and TypeScript doesn't support that construct. If not, could you be more specific?

That's especially not a problem since anyway there is no way to enforce type checking on the context related generic (you never use it in signature when you instantiate your react component)

I didn't grok this sentence for some reason. As-is, this.context has type checking.

Overall I _think_ I'm more in the camp of removing the generic type parameter. I had initial reservations about it as well since it's yet another type parameter that must be specified but rarely used. That said, I don't think having it as a type parameter is strictly wrong, it's just not user-friendly in the default case, and in the case where you do want to have context it's easy enough to add it as @fdecampredon mentions.

I didn't grok this sentence for some reason. As-is, this.context has type checking.

@jbrantly what I meant is that you have no way to enforce that a context is right from the outside of the component when you use it so basically having that in the type signature won't give you more security when instancing/using the component from the outside.

@fdecampredon Gotcha. Thanks for clarifying. Context definitely has the Hollywood Principle going. That said, the component does have to opt-in to each individual property on the context through contextTypes, so it reserves a little control. At the very least type-checking on this.context is useful for internal consistency within the component itself, although I don't think either option on the table precludes that so I guess it's a little besides the point.

I had a very short verbal discussion with @sebmarkbage on how to model context at React.js Conf. He may or may not be interested in weighing in.

After playing with this type definition and React 0.13 over the weekend, I think the Context parameter should be removed as well. There is nothing stopping people who want to use it from doing

import React = require("react");

class FrameworkComponent<P, S, C> extends React.Component<P, S> {
    protected context: C;
}

Also it's hard to envision how you can make the structural typing for contextTypes and C work out to be the same thing to use them in any meaningful way.

I think it might be a good idea to put something like that into the README though.

Agreed

I agree that structural typing for context is problematic. I think that is likely that we change it to something more map-like in the future.

var MyContext : React.Context<string> = ...;

which is accessed:

render() {
  var str : string = MyContext.get(this);
  ...
}

Referencing recent react typing contributors to get their input.
@tkrotoff @morcerf @sandersn @minestarks @mhegazy @dyst5422 @andy-ms @apexskier @yuit @janechu @p-jackson @ddwwcruz @DovydasNavickas @ericanderson

I was interested in seeing if anyone in the community felt that adding the 3rd generic parameter for context type back into the typings would be an acceptable feature now that typescript supports generic parameter defaults as of version 2.3.

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-3.html#generic-parameter-defaults

The third generic parameter for context could be defaulted as TContext = any. This would allow existing usage with just to continue as is while also providing the ability to directly specify the context type for those who wish to make use of it.

I'd be a fan of this. I currently do:

class MyComponent extends React.Component<MyComponentProps, MyComponentState> {
    context: MyComponentContext;
}

which gets the job done but doesn't allow for passing context typing information around my system

I wouldn't reject it per se. Although context is this thing that we aren't supposed to really be using so I'm not going to advocate for it either.

I feel like {} is a safer default than any for the context parameter otherwise the components will be able to grab any data. I do wish the @sebmarkbage's API existed because it feels like the right way to interact with context.

Context is kind of a backdoor for frameworks to be non-intrusive. In its current state, its easy enough to get around the type passing using @apexskier's typing above and be intentional about use of context in the implementation of those frameworks. I fear having context as a parameter indicates that it is a standard part of a React component to use and pass around, which is very much in opposition to the community stance. So I am going to reiterate what @gulbanana said two years ago:

.d.ts should follow documented usage of a library, not its implementation

i agree, unsurprisingly :)

I agree that .d.ts should follow documented usage of a library. Context, however, is a documented feature. https://facebook.github.io/react/docs/context.html

It's true that it is considered experimental/subject to change; but it is also true that it is in use in quite a few third party components/libraries that I come across. This leads me to favor supporting the third generic argument if we make it optional with a default value. I feel the default generic parameter value is a better solution for those that do use it. I also prefer the recommendation of @pspeter3 of defaulting it to {}.

I think the legacy string form of the ref prop is in a similar position to context. In the same way that the context docs begin with a section on why not to use it, the ref docs don't even mention the string form until the very end (and even then it advises against using it).

What I'm trying to say is that the parts of React that are actively advised against are still fine to add to the .d.ts, as I'm sure many people find the string form of ref to be a useful typing (although maybe a deprecated message could be added in JSDoc?)

@p-jackson I think the difference here is that there's nothing in the typings actively preventing you from using context if you choose. For refs, if we left out string then you'd have to do some ugly casting to make it work.

I'd like to bring up a recent tweet from Dan A. on the subject of context that I think points to some of the concerns brought up here.

https://twitter.com/dan_abramov/status/872109141069672448

I think when the React team itself is heavily lobbying against using context due to it being "broken", that is a concern that should be considered in the statements about documented usage.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Loghorn picture Loghorn  路  3Comments

ArtemZag picture ArtemZag  路  3Comments

Zzzen picture Zzzen  路  3Comments

lilling picture lilling  路  3Comments

variousauthors picture variousauthors  路  3Comments