question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Conditional types break with property chaining

See original GitHub issue

TypeScript 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:

Playground

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:open
  • Created 4 years ago
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
jack-williamscommented, Aug 6, 2019

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 at string and number.

0reactions
RyanCavanaughcommented, Aug 7, 2019

Truman hits the edge

Read more comments on GitHub >

github_iconTop 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 >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found