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

Use typeof with generic #20719

Closed
donaldpipowitch opened this issue Dec 15, 2017 · 3 comments
Closed

Use typeof with generic #20719

donaldpipowitch opened this issue Dec 15, 2017 · 3 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@donaldpipowitch
Copy link
Contributor

donaldpipowitch commented Dec 15, 2017

TypeScript Version: Current playground version (?)

Code

class GenericGroup<T> {
  items: Array<T> = [];
  constructor(name: string) {}
}

type CheckboxValues = string;
type CheckboxesGroup = new (name: string) => GenericGroup<CheckboxValues>;
const Checkboxes: CheckboxesGroup = GenericGroup;
const checkboxes = new Checkboxes('checkboxes');
checkboxes.items.map(item => item.toUpperCase());


type RadioValues = string;
type RadiosGroup = typeof GenericGroup<RadioValues>;
const Radios: RadiosGroup = GenericGroup;
const radios = new Radios('radios');
radios.items.map(item => item.toUpperCase());

link

Expected behavior:

typeof GenericGroup<RadioValues>; is equivalent to new (name: string) => GenericGroup<RadioValues>;

Actual behavior:

Syntax error, because typeof GenericGroup<RadioValues>; is not supported.

Motivation:

In my use case I have a class with a generic (like GenericGroup) which extends a class from a 3rd party lib. The class from the 3rd party lib uses multiple params in its constructor. When I alias my class with the filled generic I don't want to write the parameters for the 3rd party lib every time (as done with new (name: string) => GenericGroup<CheckboxValues>;) as I don't really maintain them.

(There seem to be multiple related issues, but I couldn't found an issue with exactly this problem.)

@superamadeus
Copy link

superamadeus commented Dec 15, 2017

The 'typeof' operator is not meant to describe the constructor of a type, but rather the type of a value. SomeGeneric<T> is not a value, it is a type in and of itself. Any other interface/type (like the one defined below) will not work in this way either.

interface MyInterface {
    name: string;
}

let m: typeof MyInterface; // error "MyInterface only refers to a type, but is being used as a value here."

A solution to this is to define a generic type to describe constructors like Angular does:

// angular/packages/core/src/type.ts

export interface Type<T> extends Function { 
    new (...args: any[]): T; 
}

from (angular/packages/core/src/type.ts)

Usage example:

type RadioValues = string;
type RadiosGroup = Type<GenericGroup<RadioValues>>;
const Radios: RadiosGroup = GenericGroup;
const radios = new Radios('radios');
radios.items.map(item => item.toUpperCase());

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Dec 18, 2017
@RyanCavanaugh
Copy link
Member

A subtle thing is that generic class constructor functions are not contained in a generic type. You can tell that because the type parameter is not in scope for static members! It "feels" like you have a type like this

interface GenericCtor<T> {
  new(x: string): InstanceType<T>;
}

but the real type is like this

interface GenericCtor {
  new<T>(x: string): InstanceType<T>;
}

@donaldpipowitch
Copy link
Contributor Author

Thank you both. I need to wrap my head around this. In my case I extend from a 3rd party constructor (React.Component) so I need to figure out how to apply your feedback there. Thanks.

@microsoft microsoft locked and limited conversation to collaborators Jun 21, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants