Bug Report
🔎 Search Terms
discriminated union, discriminant, interpolated template literal, contextual typing, delayed, deferred
🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about discriminated unions
⏯ Playground Link
Playground link with relevant code
💻 Code
type S = { d: "s"; cb: (x: string) => void; };
type N = { d: "n"; cb: (x: number) => void; };
declare function foo(foo: S | N): void;
foo({ d: "n", cb: x => x.toFixed() }); // okay
foo({ d: "s", cb: x => x.toUpperCase() }); // okay
foo({ d: `${"s"}`, cb: x => x.toXXX() }); // error!
// ------------------> ~
// Parameter 'x' implicitly has an 'any' type.
🙁 Actual behavior
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.
Notes
Comes from this Stack Overflow question
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:
function justS(): "s" { return "s" };
foo({ d: justS(), cb: x => x.toXXX() }); // error!
// -----------------> ~
// Parameter 'x' implicitly has an 'any' type.
Playground link
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:
const s = `${"s"}` as const;
foo({ d: s, cb: x => x.toUpperCase() }); // okay
Playground link
Mostly I'm just looking for an official status on this (and expecting it to be Design Limitation).
Bug Report
🔎 Search Terms
discriminated union, discriminant, interpolated template literal, contextual typing, delayed, deferred
🕗 Version & Regression Information
⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
In the third call to
foo(), the discriminant propertydis an interpolated template literal whose type is correctly seen to be"s", but thecbproperty's callback parameterxis not contextually typed asstringand instead implicitly falls back toany.🙂 Expected behavior
The third call to
foo()should behave just like the second call tofoo(), where the object is narrowed toSand thereforecb's parameter is contextually typed asstring.Notes
Comes from this Stack Overflow question
I'm imagining this is just a design limitation where the type of
dis computed too late for it to be available when the contextual typing forcbhappens. A similar failure occurs when the discriminant is the output of an inline function call:Playground link
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
constand use that instead:Playground link
Mostly I'm just looking for an official status on this (and expecting it to be Design Limitation).