Can I define a function generic over two types, one of which has a default, in such a way that the default gets inferred from the usage of the function if I specify the first type?
Example:
const f = <T, N extends number = number>(num: N, val: T): [N, T] => [num, val];
const e1 = f(1, "a"); // e1: [1, string] <- as expected
const e2 = f<string>(1, "b"); // e2: [number, string] <- actual
// e2: [1, string] <- desired
CodePudding user response:
Not possible currently.
You cannot partially infer generic parameters as of Typescript 4.6.2. That means that are either all inferred from usage, or all explicit.
See this github issue: https://github.com/microsoft/TypeScript/issues/10571
This cased is totally inferred:
const e1 = f(1, "a");
And this case is totally explicit:
const e2 = f<string>(1, "b");
Even though you only provide one parameter, this puts the generics in the explicit mode and it searches for other explicit sources of that parameter. And it finds one in the default type of N
, so it uses that.
The typical work around here is nested functions, which may be uglier than you want:
const fComposed = <N extends number = number>(num: N) => {
return <T>(val: T): [N, T] => {
return [num, val]
}
}
const e3 = fComposed(123)('test') // [123, string]
const e4 = fComposed(123)<string>('test') // [123, string]
All that said, this example is pretty contrived so I don't know your actual use case. But there may be a better approach entirely depending on your goal.