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
Contextual typing fails when discriminant is an interpolated template literal #53888
In the third call to foo(), the discriminant property d is an interpolated template literal whose type is correctly seen to be "s", but the cb property's callback parameter x is not contextually typed as string and instead implicitly falls back to any.
🙂 Expected behavior
The third call to foo() should behave just like the second call to foo(), where the object is narrowed to S and therefore cb's parameter is contextually typed as string.
I'm imagining this is just a design limitation where the type of d is computed too late for it to be available when the contextual typing for cb happens. A similar failure occurs when the discriminant is the output of an inline function call:
functionjustS(): "s"{return"s"};foo({d: justS(),cb: x=>x.toXXX()});// error!// -----------------> ~// Parameter 'x' implicitly has an 'any' type.
I searched around for an existing issue but I didn't find an exact enough match. There's #35769 / #41759 / #46847, for example... related but not obviously the same.
The obvious workaround is just to do the interpolation ahead of time into a const and use that instead:
This feels like one of those “you were trying to break it and succeeded” type deals that will likely not be considered worth fixing since it’s unlikely anyone would hit it by accident and/or be blocked by it (i.e. “Why would you write it this way?” ~ Future Ryan, probably)
This SO question was asked by someone who is apparently blocked by it; presumably their actual code is less contrived. I agree that it's probably not going to be considered worth addressing, though.
I'm not even sure that's a valid discriminated union? I thought the discriminant had to be a literal type (or at least a union of them), not just string.
This seems wrong; the example as presented isn't any more difficult to resolve than this one:
typeS={d: "s"|"t";cb: (x: string)=>void;};typeN={d: "n";cb: (x: number)=>void;};declareconstdv: "s"|"t";foo({d: dv,cb: x=>x.toXXX()});// does the right thing
Activity
fatcerberus commentedon Apr 18, 2023
This feels like one of those “you were trying to break it and succeeded” type deals that will likely not be considered worth fixing since it’s unlikely anyone would hit it by accident and/or be blocked by it (i.e. “Why would you write it this way?” ~ Future Ryan, probably)
jcalz commentedon Apr 18, 2023
This SO question was asked by someone who is apparently blocked by it; presumably their actual code is less contrived. I agree that it's probably not going to be considered worth addressing, though.
fatcerberus commentedon Apr 18, 2023
Hmm, while it doesn't invalidate the OP here, that SO question has this type:
I'm not even sure that's a valid discriminated union? I thought the discriminant had to be a literal type (or at least a union of them), not just
string.jcalz commentedon Apr 18, 2023
The discriminant there is an optional
undefined; you can test that it acts as a discriminated union for non-interpolatedhrefRyanCavanaugh commentedon Apr 18, 2023
This seems wrong; the example as presented isn't any more difficult to resolve than this one: