You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Can't call ((_: string) => T) | undefined when conditionally string extends T #43425
I am trying to make a generic callback function (_: string) => T, that is allowed to be optional (undefined) only when T is string. (Specifically, I chose string extends T because TS doesn't seem to provide exact equality for conditional types, and I want the default value to be (x: string) => x.)
The initial way I wrote this was string extends T ? ((value: string) => T) | undefined : (value: string) => T, but I found I was unable to (conditionally) call the function. The error seems to stem from TS treating the type as (value: T & string) => T, which prevent me from passing in a string literal.
I found a workaround that allows me to call the function: ((value: string) => T) | (string extends T ? undefined : never) (which I believe should be exactly equivalent, though let me know if this is wrong). However, this too is broken in the latest nightly, seemingly because of how NonNullable is being distributed over |:
🔎 Search Terms
generic extends function parameter union 🤷
🕗 Version & Regression Information
This changed between versions 3.8.3 and 3.9.7, and changed again between 4.2.2 and the nightly.
typeTransform1<T>=((value: string)=>T)|(stringextendsT ? undefined : never);typeTransform2<T>=stringextendsT ? ((value: string)=>T)|undefined : (value: string)=>T;functiontest<T>(f1: Transform1<T>,f2: Transform2<T>){f1?.("hello");// error in nightly, no error in 4.2.2f2?.("hello");// error since 3.9.7, no error in 3.8.3}
🙁 Actual behavior
Error on the call to f1 in 4.2.2, and errors on both calls in the nightly.
🙂 Expected behavior
Both calls should succeed. The function return value is ignored, so string extends T should have no impact on the validity of the expression.
typeTransform1<T>=((value: string)=>T)|(stringextendsT ? undefined : never);functiontest<T>(f1: Transform1<T>){f1?.("hello");// error in nightly, no error in 4.2.2}
This is indeed a regression caused by #43183. However, it was sort of halfway broken before because getNonNullableType doesn't properly eliminate higher-order types that are constrained to just 'undefined' or 'null'. For example:
Activity
jtbandes commentedon Mar 29, 2021
Unfortunately even with the workaround, the return type of my default function can't be treated as compatible with
T.RyanCavanaugh commentedon Mar 30, 2021
Tracking half of this at #43427
RyanCavanaugh commentedon Mar 30, 2021
Let's scope this one to this example
jtbandes commentedon Apr 3, 2021
I went ahead and ran a
git bisect— this broke in 15fae38 / #43183.ahejlsberg commentedon May 22, 2021
This is indeed a regression caused by #43183. However, it was sort of halfway broken before because
getNonNullableTypedoesn't properly eliminate higher-order types that are constrained to just 'undefined' or 'null'. For example:In both cases above, the type of
zshould just beNonNullable<T>because the other type is known to always be nullable.Both the regression and the above issue can be solved by being a bit smarter in
getNonNullableType.