Reputation: 312
In the following example I get Type 'string' is not assignable to type 'MapType<ReturnT>'.(2322)
. This doesn't make sense to me as the return type of the strToTs
function is basically string | number | any, depending on a different type.
type RType = 'string' | 'number';
type MapType<ReturnT extends RType> =
ReturnT extends 'string' ? string :
ReturnT extends 'number' ? number :
any;
function strToTs<ReturnT extends RType>(val: string, t: ReturnT): MapType<ReturnT> {
if (t === 'string') {
return val; // ERROR
}
return 15; // ERROR
}
const a = strToTs('test', 'string');
const b = strToTs('test', 'number');
I found some similar issues but none that really helps in this matter.
Upvotes: 0
Views: 751
Reputation: 20132
In order to solve the issue without type assertion function overloads needs to be provided.
function strToTs(val: string, t: 'number'): number
function strToTs(val: string, t: 'string'): string
function strToTs(val: string, t: 'string' | 'number'): string | number {
if (t === 'string') {
return val; // no error
}
return 15; // no error
}
const a = strToTs('test', 'string');
const b = strToTs('test', 'number');
Why this works:
string | number
so both returns are correct in that matterConditional relation between argument and return type is not possible so generic approach needs type assertion:
function strToTs<ReturnT extends RType>(val: string, t: ReturnT): MapType<ReturnT> {
if (t === 'string') {
return val as MapType<ReturnT>; // assertion
}
return 15 as MapType<ReturnT>; // assertion
}
Why conditional type does not work here. Consider plain version of the return type:
function strToTs<ReturnT extends RType>(val: string, t: ReturnT)
: ReturnT extends 'string' ? string : number {
if (t === 'string') {
return val; // error
}
return 15; // error
}
ReturnT extends 'string' ? string : number
is resolved to string
or number
correctly, but the function body return is resolved to string | number
, conditions inside the body are gathered in the union, condition inside the body of the function does not narrow the return type. That means we cannot resolved conditional type to the union never. Overloads works because implementation says return is string | number
what is exactly correct, overloaded definition are defining how function should be used with no effect on the implementation which needs to have union of all types defined in all overloads.
Upvotes: 3