Skip to content

Exclude causes infer to breakΒ #48059

Closed

Description

@bisubus

Bug Report

πŸ”Ž Search Terms

infer, Exclude, conditional typing

πŸ•— Version & Regression Information

  • This changed between versions 3.8.3 and 3.9.7

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

type Simplify<T> = {[KeyType in keyof T]: T[KeyType]};

type optionalKeys<T extends object> = {
    [k in keyof T]: undefined extends T[k] ? k : never;
}[keyof T];

type requiredKeys<T extends object> = Exclude<keyof T, optionalKeys<T>>;

export type addQuestionMarks<T extends object> = {
    [k in optionalKeys<T>]?: T[k];
} & {
    [k in requiredKeys<T>]: T[k];
};

type ZodRawShape = {
    [k: string]: ZodType<any>;
};

interface ZodType<Output> {
  _type: Output;
}

interface ZodObject<
  T extends ZodRawShape,
  Output = Simplify<
    {
      [k in optionalKeys<T>]?: T[k];
    } & {
      [k in requiredKeys<T>]: T[k];
    }
  >
> extends ZodType<Output> {
  readonly _shape: T;
}

type MyObject<T> = T extends ZodObject<infer U>
  ? U extends ZodRawShape
    ? U
    : never
  : never;

πŸ™ Actual behavior

infer U causes an error with requiredKeys using Exclude utility type:

Type 'U' does not satisfy the constraint 'ZodRawShape'.(2344)

The same inference works when requiredKeys is simplified to:

type requiredKeys<T extends object> = {
  [k in keyof T]: undefined extends T[k] ? never : k;
}[keyof T];

The problem disappears when some type manipulations (Simplify, k in optionalKeys<T>, k in requiredKeys<T>) are removed.

πŸ™‚ Expected behavior

Both requiredKeys implementations are expected to work similarly.

Activity

  1. RyanCavanaugh commented on Feb 28, 2022

    @RyanCavanaugh
    Member

    Wanted: a shorter repro to produce a constraint violation on a T<infer U> expression

  2. RyanCavanaugh commented on Feb 28, 2022

    @RyanCavanaugh
    Member

    This is as good as I can get it:

    type AMappedType<T> = { [KeyType in keyof T]: number };
    
    type HasM = {
      m: number;
    };
    
    interface X<T extends HasM, Output = AMappedType<{ s: number; } & { [k in keyof T]: number; }>> {
      tee: T;
      output: Output;
    }
    
    type F<T> = T extends X<infer U> ? U : never;

    The lack of error elaboration here is particularly frustrating

  3. locked as resolved and limited conversation to collaborators on Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions