Reputation: 161
Anyone can help me? This is 3 examples: a, b, c. For first and second "arg" type is true (number). For third version typescript can't resolve type for "arg".
function a<T extends (value: number) => string>(
arg: T,
) {
return null;
}
a((arg) => arg.toExponential()); // ARG HAS RIGHT TYPE: number
function b<T extends { [index: string]: (value: number) => string }>(
arg: T,
) {
return null;
}
b({ x: (arg) => arg.toExponential() }); // ARG HAS RIGHT TYPE: number
function c<K extends { [index: string]: number }, T extends {[P in keyof K]?: ((value: number) => string) }>(
arg1: K,
arg2: T,
) {
return null;
}
c({ x: 15 }, { x: (arg) => arg.toExponential() }); // ARGS NOT HAS TYPE: any
Upvotes: 2
Views: 57
Reputation: 249536
The compiler gets a bit confused when the two type parameters have a dependency and one needs to be inferred dependent on the other. A simple work around I use is to do a two step call, the first function fixes the first argument type and the second call can have the rest of the type inferred:
function c<K extends { [index: string]: number }>(arg1: K)
{
return function <T extends {[P in keyof K]?: ((value: number) => string) }>(arg2: T){
};
}
c({ x: 15 })({ x: (arg) => arg.toExponential() }); // arg will be number
Edit
Although the above solution works and correctly infers T
, as suggested by @MihailMalostanidis, it might not be necessary in this case to use the second parameter at all. This also infers correctly:
function c<K extends { [index: string]: number } >(
arg1: K,
arg2: {[P in keyof K]?: ((value: number) => string) },
) {
return null;
}
The difference is that if you were to return arg2
from the function (or a type based on T
), in this version all keys of K
would be present, not just those actually specified in arg2
when called. Depending on your use case, this may be acceptable, but the initial solution is applicable in all cases.
Upvotes: 4