The following Typescript code snippet produces an error
function importedF<R extends string>(a: R extends string ? number : never) {}
function genericF<T extends string>() {
importedF<T>(1);
}
where the error is on the parameter 1
passed to importedF
and reads
Argument of type 'number' is not assignable to parameter of type 'T extends string ? number : never'.ts(2345)
Please help me understand why Typescript doesn't understand that T
is indeed a string
and thus the conditional statement should result in number
. I'm looking for understanding rather than workaround.
The following Typescript code snippet produces an error
function importedF<R extends string>(a: R extends string ? number : never) {}
function genericF<T extends string>() {
importedF<T>(1);
}
where the error is on the parameter 1
passed to importedF
and reads
Argument of type 'number' is not assignable to parameter of type 'T extends string ? number : never'.ts(2345)
Please help me understand why Typescript doesn't understand that T
is indeed a string
and thus the conditional statement should result in number
. I'm looking for understanding rather than workaround.
2 Answers
Reset to default 1This is considered a design limitation of TypeScript, as described at microsoft/TypeScript#51523 and issues linked within.
If you have a conditional type that depends on a generic type parameter, TypeScript mostly just defers evaluation of it. Inside genericF()
, T
is generic, and TypeScript doesn't know exactly what it is yet, so the relevant type T extends string ? number : never
is deferred. TypeScript doesn't even try to evaluate it. You might hope that because T
has a constraint TypeScript could use it to partially (or wholly) evaluate the type instead of deferring it, but that doesn't happen. So TypeScript doesn't know what might be assignable to T extends string ? number : never
, and it complains about 1
.
As mentioned in the comments TS doesnt handle well conditional types with generics, you could overload the function. Also it's not clear why you need the conditional type, since R
always a string. Given that R
could be also any
:
Playground
function importedF<R extends string>(a: number): void;
function importedF<R extends any>(a: never): void;
function importedF(a: number):void {
}
function genericF<T extends string>() {
importedF<T>(1);
}
importedF
. If you can't do that, then use a type assertion or something non-generic like this playground link. Please edit to clarify your primary question (it really can't be "both" because then you invite multiple answers), and let me know how you'd like to proceed. – jcalz Commented Feb 28 at 20:34