Typescript: Support passing typeof T as parameter in generic methods

Created on 10 Oct 2016  路  4Comments  路  Source: microsoft/TypeScript

TypeScript Version: 2.0.3

linq.d.ts:

interface Array<T> {
  ofType<TResult>(type:typeof TResult):TResult[]
}

Expected behavior:
No errors.

Actual behavior:
produces error:

[ts] Cannot find name 'TResult'.

Question

Most helpful comment

@aluanhaddad I think @MeirionHughes probably want something like this, if I read the C# counterpart correctly.

interface Array<T> {
  ofType<R extends T>(RType: { new(...args: any[]): R}): R[] 
 // probably you also need overloading for builtin Number, String, Boolean
}

//usage
var animals: Animal[] = [new Cat, new Dog, new Fish]
var cats: Cat[] = animals.ofType(Cat)

Please first checkout FAQ before submitting issues. You probably want to pass a constructor to ofType so that array values can be filtered at runtime.

@aluanhaddad I think your approach can only make Array<TResult> but not runtime. C#'s generic is reified at runtime, but TypeScript's is erased. So users must have a value to figure out which type should be used as filter criteria.

All 4 comments

@MeirionHughes If you are after behavior analogous to C#'s
IEnumerable<TResult> Enumerable.OfType<TResult>(this IEnumerable<T>);
you can simply write

interface Array<T> {
  ofType<TResult>(): TResult[];
}

The reason you get the error

[ts] Cannot find name 'TResult'.

is because typeof expects a value and TResult is a type. For example, when acting upon a class, the case where it is most commonly used, it is the class's value that is the operand.

@aluanhaddad I think @MeirionHughes probably want something like this, if I read the C# counterpart correctly.

interface Array<T> {
  ofType<R extends T>(RType: { new(...args: any[]): R}): R[] 
 // probably you also need overloading for builtin Number, String, Boolean
}

//usage
var animals: Animal[] = [new Cat, new Dog, new Fish]
var cats: Cat[] = animals.ofType(Cat)

Please first checkout FAQ before submitting issues. You probably want to pass a constructor to ofType so that array values can be filtered at runtime.

@aluanhaddad I think your approach can only make Array<TResult> but not runtime. C#'s generic is reified at runtime, but TypeScript's is erased. So users must have a value to figure out which type should be used as filter criteria.

@HerringtonDarkholme yes, that { new(...args: any[]): R works perfectly.

is because typeof expects a value and TResult is a type. For example, when acting upon a class, the case where it is most commonly used, it is the class's value that is the operand.

Okay thx, I'll close this then.

@HerringtonDarkholme great point, I was being overly literal. Another, perhaps more flexible approach would be to take a typeguard as the argument.

interface Array<T> {
  ofType<TResult extends T>(guard: (x: T) => x is TResult): TResult[];
}
Was this page helpful?
0 / 5 - 0 ratings