arvitaly
arvitaly

Reputation: 161

Why not resolved type for argument of function, which element of object (typescript)?

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

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

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

Related Questions