Conditional types break with property chaining
See original GitHub issueTypeScript Version: 3.5.1
Search Terms:
property chaining, generic, object type param, conditional type
Code
Modified version of @fatcerberus ’ attempt to break TS.
type Droste<T extends {x:number|string}> = {
value: T,
/**
* Should alternate between string and number
*/
droste: Droste<{x:(T["x"] extends number ? string : number)}>
};
declare const droste: Droste<{x:number}>;
//number
const _0 = droste.droste.droste.droste.droste.droste.droste.droste.droste.droste.droste
.droste.droste.droste.droste.droste.droste.droste.droste.droste.droste
.droste.droste;
const _1 = _0.droste; //string
const _2 = _1.droste; //number
const _3 = _2.droste; //string
const _4 = _3.droste; //Expected number, actual string, ???
const _5 = _4.droste; //string
const _6 = _5.droste; //string
const _7 = _6.droste; //string
const _8 = _7.droste; //string
const _9 = _8.droste; //string
//string forever and ever. Where is `number`?
Expected behavior:
Each access to .droste
should alternate between string
and number
.
Or give a max instantiation depth/count error.
Actual behavior:
It alternates between string
and number
and then breaks after while.
From that point, it just sticks with string
.
No errors given.
Playground Link:
Related Issues:
It is similar to https://github.com/microsoft/TypeScript/issues/32707
Except, it gives up and resolves the type to string
, rather than any
.
Issue Analytics
- State:
- Created 4 years ago
- Comments:7 (5 by maintainers)
Top Results From Across the Web
Optional chaining (?.) - JavaScript - MDN Web Docs - Mozilla
This results in shorter and simpler expressions when accessing chained properties when the possibility exists that a reference may be missing.
Read more >TypeScript and JavaScript conditional chaining
The phrase "conditional chaining" is a misnomer used to describe two features - optional chaining and non-null assertion chaining.
Read more >TypeScript and JavaScript conditional chaining - JS.dev
The phrase “conditional chaining” is a misnomer used to describe two features - optional chaining and non-null assertion chaining.
Read more >Documentation - TypeScript 3.7
The other type of assertion signature doesn't check for a condition, but instead tells TypeScript that a specific variable or property has a...
Read more >5 Ways Converting to Optional Chaining Can Break Your Code
The optional chaining operator .? returns the value of an object property when the object is available and undefined otherwise.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
If I had to guess (and it really is a guess), there is a caching of instantiations done on type id. With your original example you create a new object literal type (with a new id) for each recursive instantiation that will have no cached value.
In the modified example each the recursion goes through
NextDrosteFix
which is instantiated with a primitive type (and primitive types are interned).NextDrosteFix
will be cached for the instantiations atstring
andnumber
.