Skip to content

[4.3, 4.4] Inline filtering mapped type conditional with infer fails #46020

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

Open
phroggyy opened this issue Sep 23, 2021 · 0 comments
Open

[4.3, 4.4] Inline filtering mapped type conditional with infer fails #46020

phroggyy opened this issue Sep 23, 2021 · 0 comments
Assignees
Labels
Bug A bug in TypeScript Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@phroggyy
Copy link

phroggyy commented Sep 23, 2021

Bug Report

As of TypeScript 4.3, when inlining a mapped type on the left-hand side of extends in a conditional type, TypeScript incorrectly evaluates the condition when the right-hand side contains another mapped type with infer and renders the false condition. When declaring the mapped type explicitly rather than inline, the ternary is correctly evaluated.

This is pretty hard to cover in words, so please check playground link for reproduction.

The language version can be changed to 4.2 to see it working correctly.

🔎 Search Terms

typescript infer inline mapped type never generic inference

🕗 Version & Regression Information

  • This changed between versions 4.2 and 4.3

⏯ Playground Link

Change TS language to 4.2 to see the code functioning correctly, and 4.3 or 4.4 to see failure.

Playground link with relevant code

💻 Code

type DefinedKeys<T> = {
  [K in keyof T]:
    string extends K ? never :
    number extends K ? never :
  K }

type KnownKeys<T> = DefinedKeys<T> extends {
    [_ in keyof T]: infer U
  }
  ? U
  : never;

// This type is the exact same as `KnownKeys`, but inlines `DefinedKeys<T>` instead of declaring it as a separate type
type FailingKnownKeys<T> = {
  [K in keyof T]:
    string extends K ? never :
    number extends K ? never :
  K } extends {
    [_ in keyof T]: infer U
  }
  ? U
  : never;

interface Flags {
  knownFlag1: boolean
  knownFlag2: boolean
  [x: string]: boolean | null | undefined;
}

type DefinedValidationKeys = DefinedKeys<Flags>
type KnownFlags = KnownKeys<Flags>
type FailingKnownFlags = FailingKnownKeys<Flags>

🙁 Actual behavior

In the above code sample, the type FailingKnownFlags is never (the false branch of the ternary of FailingKnownKeys<T>), while KnownFlags correctly is {knownFlag1: boolean, knownFlag2: boolean}

🙂 Expected behavior

KnownKeys<T> === FailingKnownKeys<T>

They are the same declaration, just one being inline and the other with an explicitly extracted type.

@sandersn sandersn added Bug A bug in TypeScript Needs Investigation This issue needs a team member to investigate its status. labels Oct 6, 2021
@sandersn sandersn added this to the TypeScript 4.6.0 milestone Oct 6, 2021
@sandersn sandersn self-assigned this Oct 6, 2021
@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label May 13, 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 Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

No branches or pull requests

3 participants