I can't understand something about TypeScript's type inference. I thought this should be valid and wouldn't require me to specify the type of T
:
export const deflt = <T>(val: (T | undefined | null), defaultVal: T): T => {
if (val === undefined || val === null) {
return defaultVal;
}
return val;
}
function maybeLabelName(name: string | undefined) {
return deflt(name, 'untitled');
}
The call to deflt fails with the following error:
Argument of type 'string | undefined' is not assignable to parameter of type '"untitled" | null | undefined'.
Type 'string' is not assignable to type '"untitled" | null | undefined'. [2345]
I can fix it by changing the deflt
call to one of the following:
// Option 1:
return deflt<string>(name, 'untitled');
// Option 2:
const s: string = 'untitled';
return deflt(name, s);
Shouldn't TypeScript infer the string
type automatically?
I think this is a bit of a quirk in the way typescript infers T
in this case. Because you specify the constant 'untitled'
, the compiler will infer T
as the string literal type 'untitled'
, since that is the simplest site to infer T
from. It will then check the other parameter against the string literal type and find that string
is not assignable to 'untitled'
. A work around would be to decrease the priority of the second parameter when inferring T
by adding an extra intersection with {}
:
export const deflt = <T>(val: (T | undefined | null), defaultVal: T & {} ): T => {
if (val === undefined || val === null) {
return defaultVal;
}
return val;
}
function maybeLabelName(name: string | undefined) {
return deflt(name, 'untitled'); // T is string now
}
Another solution (if ou can't change the original function) would be to explicitly assert untitled
to string
, which is basically what you already tried.
function maybeLabelName(name: string | undefined) {
return deflt(name, 'untitled' as string); // T is string now
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With