Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Conditional types throw error since TS 4.9.x #51614

Closed
jxn-30 opened this issue Nov 21, 2022 · 4 comments Β· Fixed by #51621
Closed

[Bug] Conditional types throw error since TS 4.9.x #51614

jxn-30 opened this issue Nov 21, 2022 · 4 comments Β· Fixed by #51621
Assignees
Labels
Bug A bug in TypeScript

Comments

@jxn-30
Copy link

jxn-30 commented Nov 21, 2022

Bug Report

πŸ”Ž Search Terms

conditional types, 2339

πŸ•— Version & Regression Information

  • This changed between versions 4.8.4 and 4.93
  • This bug also occurs on nightly version 5.0.0-dev.20221121

⏯ Playground Link

Playground link with relevant code and test cases

πŸ’» Code

// Errors in TS 4.9.3 but not in 4.8.4
interface A {}
type B = A extends Record<'foo', string> ? A['foo'] : string; // Error: Property 'foo' does not exist on type 'A'.(2339)

// Succeeds in TS 4.9.3 and 4.8.4
interface C { foo: number; }
type D = C extends Record<'foo', string> ? C['foo'] : string; // Correct: string

// Succeeds in TS 4.9.3 and 4.8.4
interface E { foo: string; }
type F = E extends Record<'foo', string> ? E['foo'] : string; // Correct: string

// Succeeds in TS 4.9.3 and 4.8.4
interface G { foo: 'bar'; }
type H = G extends Record<'foo', string> ? G['foo'] : string; // Correct: 'bar'

πŸ™ Actual behavior

interface A {}
type B = A extends Record<'foo', string> ? A['foo'] : string;

errors with 2339: Property 'foo' does not exist on type 'A'.

This change causes @vuejs/pinia to fail as one can see in vuejs/pinia#1814

πŸ™‚ Expected behavior

interface A {}
type B = A extends Record<'foo', string> ? A['foo'] : string;

returns with B being an alias for type string.

@MartinJohns
Copy link
Contributor

Workaround: A extends Record<'foo', infer X extends string> ? X : string

@ahejlsberg
Copy link
Member

This is working as intended. In cases where the outcome of a conditional type is known to always be the false branch, we no longer pretend that the type in the true branch has satisfied the extends check. In the example that produces an error above, the outcome of the conditional type is always the false branch string, and in the true branch we no longer pretend it is possible to write A['foo'] because that property is known not to exist. I think this is preferable to allowing nonsense like this:

type T0 = Number extends String ? Number["length"] : String["length"];  // This was previously ok but now errors

I understand there's a possible usage pattern where the conditional type is a form of conditional compilation based on types declared elsewhere in the program, but in those cases I think it is reasonable to require an explicit intersection:

type B = A extends Record<'foo', string> ? (A & Record<'foo', string>)['foo'] : string;

@ahejlsberg ahejlsberg added the Working as Intended The behavior described is the intended behavior; this is not a bug label Dec 6, 2022
@Andarist
Copy link
Contributor

Andarist commented Dec 6, 2022

@ahejlsberg what about interface augmentation though? With it, the type checker can't actually prove that the outcome of this conditional type is always its false branch. The conditional type can live in the library's code and the augmentation might happen in the consuming application. It seems that this is exactly how this was used here.

In general, I agree with your reasoning but when providing the fix, I assumed that this was meant to be supported exactly because of the interface augmentation.

@ahejlsberg
Copy link
Member

what about interface augmentation though?

Yeah, although unintended, I agree that's meaningful scenario. Let's call this a regression then and merge your PR.

@ahejlsberg ahejlsberg added Bug A bug in TypeScript and removed Working as Intended The behavior described is the intended behavior; this is not a bug labels Dec 7, 2022
@ahejlsberg ahejlsberg self-assigned this Dec 7, 2022
@ahejlsberg ahejlsberg added this to the TypeScript 5.0.0 milestone Dec 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants