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[]>; }'.
maybe related to https://github.com/Microsoft/TypeScript/issues/12424
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.
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
thisparameter.