Skip to content

Infer returns wrong type in 4.2.* #43161

Closed

Description

@Lehks

Bug Report

With a particular type-setup, infer does not provide the correct type. When you open the playground link, you will see the type Opts and the types ExtractReq and ExtractOpt. Opts takes two type parameters, Required and Optional and ExtractReq and ExtractOpt will extract these two types using infer. However, the extracted types are, for the most part, incorrect.

🔎 Search Terms

infer, generic

🕗 Version & Regression Information

After updating TS to version 4.2.*. I have tried the nightly version and the problem did still arise.

  • This changed between versions 4.1.2 and 4.2.2

⏯ Playground Link

Playground link with relevant code

💻 Code

// Opts type:
type Opts<
    Required extends Record<string, unknown> | Never = Never,
    Optional extends Record<string, unknown> | Never = Never
> = Required & Partial<Optional>;

// extract types
type ExtractReq<T> = T extends Opts<infer Required, any> ? Required : never;
type ExtractOpt<T> = T extends Opts<any, infer Optional> ? Optional : never;

// shortand for Opts type with specific type parameters
type Opts3 = Opts<{ a: string }, { b: string }>;

// this type is Partial<{ a: string }> & Partial<{ b: string }> although { a: string } was expected.
type Req3 = ExtractReq<Opts3>;

// this type is Never | Record<string, unknown> although { b: string } was expected.
type Opt3 = ExtractOpt<Opts3>;

🙁 Actual behavior

The types that are inferred by ExtractReq and ExtractOpt are incorrect (see code above / playground link).

🙂 Expected behavior

The type { a: string } in the case of Req3 and { b: string } in the case of Opt3.

Activity

  1. RyanCavanaugh commented on Mar 9, 2021

    @RyanCavanaugh
    Member

    Once you've mixed two types together into a new type, you can't "unmix" them this way unless some very particular conditions (i.e. ones you shouldn't rely on) are met. Our type alias preservation changes in 4.2 changed this example from a "happens to work" to a "happens to not work".

  2. typescript-bot commented on Mar 12, 2021

    @typescript-bot
    Contributor

    This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  3. FlyingPumba commented on Jul 7, 2021

    @FlyingPumba
    Contributor

    Ryan Cavanaugh (@RyanCavanaugh) is there any other, more proper, way to "unmix" the types of a composed type as mentioned by OP.
    E.g., from a type that is a Opts<T, Q>, obtain the particular T and Q.
    I also had (important) code relying on this feature, and it stopped working after updating TS to 4.2.

    It would be good to put a big red warning in TS documentation: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#type-inference-in-conditional-types
    AFAIK, this is a listed feature, not just a "happens to work" feature.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions