-
Notifications
You must be signed in to change notification settings - Fork 13k
Description
(sorry for poor titling - not sure what it should be :) )
Bug Report
🔎 Search Terms
type hints, templates, expanded types / expansion, intersections, conditionals
🕗 Version & Regression Information
This is the behavior in every version I tried (including the nightly build), and I reviewed the FAQ for entries about type hints.
Additionally, I observed it in both TS playground and VSC.
⏯ Playground Link
Playground link with relevant code
(Edited since initial issue to include functions and ^?
)
💻 Code
I have types that I want to change depending on a string literal that is passed in via a template argument. The actual details of how this string is parsed is being left out as it is not relevant.
The type hint (what shows when you hover over a variable in an editor / TS playground) has inconsistent behavior surrounding this. The actual type information is correct. I want the types following to show as their un-expanded forms (i.e. Game<"">
and Game<"categories">
)
What I'm currently doing / what I expect to work: GameA<"">
shows expanded, but GameA<"categories">
doesn't.
type GameA<Embed extends string = ""> = {
id: string;
name: string;
}
& (Embed extends "categories" ? { categories: string[] } : {});
const a = {} as GameA; // incorrect - expect type hint to be Game<"">, but shows { id: string; name: string; }!
const b = {} as GameA<"categories">; // correct - type hint shows as Game<"categories">
a.categories; // correct - error (no property)
b.categories; // correct - no error (categories exists and is string[])
A workaround I have found:
type GameB<Embed extends string = ""> = {
id: string;
name: string;
}
& { id: string; }
& (Embed extends "categories" ? { categories: string[] } : {});
const c = {} as GameB; // correct - type hint shows as Game<"">
const d = {} as GameB<"categories">; // correct - type hint shows as Game<"categories">
c.categories; // correct - error (no property)
d.categories; // correct - no error (categories exists and is string[])
🙁 Actual behavior
Variables of type GameA<"">
show up in type hints as { id: string; name: string; }
and variables of type GameA<"categories">
show up in type hints as GameA<"categories">
. This is inconsistent!
Intersecting this type with an arbitrary non-empty object causes them to both show up as unexpanded, despite their type not actually changing. In this example the non-empty objects contains a duplicate property, but it does not have to be duplicate to fix it.
GameA
also is expanded as the return value for functions (when inferred):
🙂 Expected behavior
I expected variables of type GameA<"">
and GameA<"categories">
to both show up in type hints as just that. (i.e., I expected the behavior of GameB
for GameA
, and for GameB
to be identical to GameA
in all aspects)
And for return values of functions, same logic:
Note that I want the behavior of un-expanded form here, because I find it much more readable / useful! In my actual project, it looked something like this:
(I have fixed this in my project using the GameB
workaround).