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());
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.)
The 'typeof' operator is not meant to describe the constructor of a type, but rather the type of a value. SomeGeneric
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());
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>;
}
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.
Most helpful comment
The 'typeof' operator is not meant to describe the constructor of a type, but rather the type of a value. SomeGeneric 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.
A solution to this is to define a generic type to describe constructors like Angular does:
from (angular/packages/core/src/type.ts)
Usage example: