Typescript: Specialize declared generic interfaces based on parameter shape

Created on 2 Feb 2017  ·  4Comments  ·  Source: microsoft/TypeScript

For typing something like underscore's _.chain, it would be helpful if interfaces could be extended based on the shape of their type parameters.

For example:

// These methods are available for any T.
declare interface Chainable<T> {
  value(): T;
}

// These methods are only available for array types.
declare interface Chainable<T[]> {
  map<U>(mapFn: (t: T) => U): Chainable<U[]>;
}

Existing type definitions try to infer whether T is an array, object, array of objects, etc. But this is cumbersome and they'll never be able to do it as well as TypeScript itself.

The snippet above doesn't parse with TypeScript 2.1.5:

[ts] Operator '>' cannot be applied to types 'undefined[]' and '{ map<U>(mapFn: (t: any) => U): Chainable<U[]>; }'.
In Discussion Suggestion

Most helpful comment

I wrote a post that touched on this issue and got some great feedback from the /r/javascript reddit. As it turns out, there's a workaround that already works: specialize by overloading the this parameter.

declare interface Chainable<T> {
  value(): T;  // This methods is available for any T.

  // This method is only available for array types, where T matches V[].
  map<U, V>(this: Chainable<V[]>, mapFn: (v: V) => U): Chainable<U[]>;
}

All 4 comments

either #12424 or have some sort of overload on generic type parameters

I wrote a post that touched on this issue and got some great feedback from the /r/javascript reddit. As it turns out, there's a workaround that already works: specialize by overloading the this parameter.

declare interface Chainable<T> {
  value(): T;  // This methods is available for any T.

  // This method is only available for array types, where T matches V[].
  map<U, V>(this: Chainable<V[]>, mapFn: (v: V) => U): Chainable<U[]>;
}

Overloading on the type of this works great. The lodash declarations in DefinitelyTyped do this now. Closing.

Was this page helpful?
0 / 5 - 0 ratings