Repository navigation
[4.3, 4.4] Inline filtering mapped type conditional with infer fails #46020
Description
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.
Activity
RyanCavanaugh commentedon Sep 8, 2026
This is a duplicate of #44143. Both examples use the same inline mapped key filter on the left side of
extends { [_ in keyof T]: infer U }, which causes the inferred result to becomeneverafter TypeScript 4.3.