Closed jelbourn closed 3 months ago
Typescript will not infer type parameters if they are not used in the parameters of the function. Other type parameters are not (as far as I know) an inference site for type parameters.
There are several ways of getting the code above to work. You could just use D
and remove T
:
interface HasId {
id: string;
}
interface SpecialArray<D> {
getSpecialItem(): D;
}
function go<D>(x: D[]): SpecialArray<D> {
return x as any;
}
const v: Array<HasId> = [{id: 'one'}];
const w = go(v); //SpecialArray<HasId>
Or use T
and use a conditional type to extract the item type:
function go<T extends any[]>(x: T): SpecialArray<T extends Array<infer D> ? D : never> {
return x as any;
}
const v: Array<HasId> = [{id: 'one'}];
const w = go(v); //SpecialArray<HasId>
While it would be nice if your code would work as is, since there are already ways to achieve the same thing I'm not sure the extra complexity to infer one type parameter from the other is justified.
@dragomirtitian 's analysis is correct.
Without use cases that require new functionality, there's not really a suggestion here. Generic functions are already inferred in many places where appropriate, but the function described in OP doesn't need that.
Search Terms
generic, propagate, multiple, preserve, argument, parameter, pass-through
Suggestion
When a generic function expresses its return type in terms of an argument constraint, the originally given argument type should be preserved/passed-through when the function is called.
Example
([playground](https://www.typescriptlang.org/play/#src=%0D%0Ainterface%20HasId%20%7B%0D%0A%20%20id%3A%20string%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20SpecialArray%3CD%3E%20%7B%0D%0A%20%20getSpecialItem()%3A%20D%3B%0D%0A%7D%0D%0A%0D%0Afunction%20go%3CT%20extends%20Array%3CD%3E%2C%20D%3E(x%3A%20T)%3A%20SpecialArray%3CD%3E%20%7B%0D%0A%20%20return%20x%20as%20any%3B%0D%0A%7D%0D%0A%0D%0Aconst%20v%3A%20Array%3CHasId%3E%20%3D%20%5B%7Bid%3A%20'one'%7D%5D%3B%0D%0A%0D%0A%2F%2F%20We%20expect%20a%20return%20type%20of%20%60SpecialArray%3CHasId%3E%60%20but%20instead%20we%0D%0A%2F%2F%20get%20%60SpecialArray%3C%7B%7D%3E%60.%0D%0Aconst%20w%20%3D%20go(v)%3B))
Use Cases
My primary use-case for this has been compositional mixins. I want to be able to take some class with a type like
HasItems<SomeItem>
and augment it with a mixin to add a behaviorHasActiveItem<D>
, where the mixin has recognizes theSomeItem
passed in and propagates it through to satisfy subsequent mixin calls.This can be done today by omitting one of the generics from the function signature and duplicating those bits of typing in both the parameters and the return type; the remaining generic only captures the "Item" part of the signature.
Checklist