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

Allow static members to reference class type parameters #24018

Closed
jaredru opened this issue May 10, 2018 · 5 comments
Closed

Allow static members to reference class type parameters #24018

jaredru opened this issue May 10, 2018 · 5 comments
Labels
Declined The issue was declined as something which matches the TypeScript vision

Comments

@jaredru
Copy link

jaredru commented May 10, 2018

Search Terms

static, generic, type, getDerivedPropsFromState

Suggestion

Static class members should be allowed to reference the class's type parameters.

Use Cases

React 16.3 introduced a static lifecycle method to Component. Its definition should look something like:

class Component<P, S> {
  static getDerivedStateFromProps?(p: P, s: S): Partial<S> | null;
}

However, that definition results in compiler error TS2302 "Static members cannot reference class type parameters", so it doesn't exist on the DefinitelyTyped definition for Component. In practice, this means we get less help from the editor in the form of code completion, and we get less type safety, as it's possible to misdefine the types when implementing getDerivedStateFromProps.

FWIW, Flow supports this.

Examples

Checklist

My suggestion meets these guidelines:
[x] This wouldn't be a breaking change in existing TypeScript / JavaScript code
[x] This wouldn't change the runtime behavior of existing JavaScript code
[x] This could be implemented without emitting different JS based on the types of the expressions
[x] This isn't a runtime feature (e.g. new expression-level syntax)

@ghost
Copy link

ghost commented May 10, 2018

Without inheritance that wouldn't make much sense:

class Super<T> {
    static m(x: T): void;
}
Super.m(); // What's `T`?

I see what you mean though, when a subclass is introduced:

class Sub extends Super<number> {}
Sub.m(); // T is number

Although we can't be sure that a subclass will actually provide a concrete type argument and not just another type parameter.

Could you maybe flesh out your example into something independent from react?

(By the way, seems like this issue might be related to #14600.)

@mhegazy mhegazy added the Declined The issue was declined as something which matches the TypeScript vision label May 10, 2018
@jaredru
Copy link
Author

jaredru commented May 10, 2018

In your example, I would expect it to be inferred:

class Super<T> {
    static m(x: T): void;
}
Super.m();  // Error: Expected 1 argument, but got 0.
Super.m(3); // `T` is number

As a return type, where you can't infer it, I would expect the same functionality as a normal "static"/free function:

function fn<T>(): T;
const a = fn(); // a is typed to {}
const b = fn<number>(); // b is typed to `number`

I understand the "danger" of that - it's effectively a lie, given that there's no runtime information available to fn to actually return the appropriate type - but that syntax is allowed today.

Thank you for the link to #14600. This does seem related, and it might even be safer to only allow abstract static methods to utilize class type params.

Could you maybe flesh out your example into something independent from react?

May I ask why? My motivation is React. I could spend time coming up with a separate contrived example, but really I'd like working with React to require as few concessions as possible.

@RyanCavanaugh
Copy link
Member

@jaredru if you want that behavior, you can write

class Super<T> {
    static m<U>(x: U): void;
}

The only thing trying to use Super's T does is change a call that should look like this:

foo.bar<T>(expr);

into this

foo<T>.bar(expr);

@jaredru
Copy link
Author

jaredru commented May 10, 2018

Right, except in the subclass case, which is the React case.

I think you all are right that this ticket is not really what I want. Ultimately, what I'd like is a way to accurately type React's new lifecycle method. So perhaps I should ask, simply, is this something you're thinking about? It seems to me abstract static getDerivedStateFromProps?(p: P, s: S): Partial<S> | null; would work well, but perhaps there's an issue with that, too, even in the face of the use case.

@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Declined The issue was declined as something which matches the TypeScript vision
Projects
None yet
Development

No branches or pull requests

4 participants