GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Conditional type inference regression in 4.2* · Issue #43192 · microsoft/TypeScript

Conditional type inference regression in 4.2* #43192

New issue
Copy link
New issue
Copy link
Closed
Closed
Conditional type inference regression in 4.2*#43192
Copy link
Assignees
ahejlsberg
Labels
Breaking ChangeWould introduce errors in existing codeWould introduce errors in existing codeWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug

Description

@robertf224
Robert Fidler (robertf224)
opened on Mar 11, 2021
Issue body actions

Bug Report

🔎 Search Terms

"conditional type inference"

🕗 Version & Regression Information

This changed between versions 4.1.5 and 4.2.2

⏯ Playground Link

Playground link with relevant code

💻 Code

export interface IFruits {
    tropical: {
        papaya: number;
        pineapple: number;
        guava: number;
    };

    stone: {
        peach: number;
        nectarine: number;
    };

    berry: {
        strawberry: number;
        blueberry: number;
    };
}

/**
 * Aggregating all the second level keys (the fruits) into a single union type.
 */
export type FruitKey = {
    [category in keyof IFruits]: keyof IFruits[category];
}[keyof IFruits];

/**
 * Helper to pick only fruit categories (first level) that are required for the requested fruit keys.
 */
type RequiredFruitCategories<K extends FruitKey> = {
    [category in keyof IFruits]: Extract<K, keyof IFruits[category]> extends never ? never : category;
}[keyof IFruits];


/**
 * Takes a nested slice of the IFruits interface depending on the fruit keys (second level) that
 * we ask for -- essentially a nested `Pick`.  So `FruitsSubset<"papaya" | "peach">` ends up being:
 * {
 *      tropical: {
 *          papaya: number;
 *      };
 *      stone: {
 *          peach: number;
 *      };
 * }
 */
type FruitsSubset<K extends FruitKey> = {
    [category in RequiredFruitCategories<K>]: Pick<
        IFruits[category],
        Extract<K, keyof IFruits[category]>
    >;
};

/**
 * Just wrapping the above in an interface for other interfaces (i.e. React props) to extend.
 */
interface FruitsSubsetOpts<K extends FruitKey> {
    fruits: FruitsSubset<K>;
}

type MyFavoriteFruitsSubset = FruitsSubset<"papaya" | "peach">;
// Inferring the key from above -- this ends up being `"papaya" | "peach"` on TS 4.1.5 but `never` on 4.2.3
type MyFavoriteFruitsSubsetKey = MyFavoriteFruitsSubset extends FruitsSubset<infer K> ? K : never;

type MyFavoriteFruitsSubsetOpts = FruitsSubsetOpts<"papaya" | "peach">;
// Inferring the key from above -- this ends up being `"papaya" | "peach"` on both TS 4.1.5 and 4.2.3
// Pretty confusing because FruitsSubsetOpts is just a wrapper around FruitsSubset!
type MyFavoriteFruitsSubsetOptsKey = MyFavoriteFruitsSubsetOpts extends FruitsSubsetOpts<infer K> ? K : never;

🙁 Actual behavior

MyFavoriteFruitsSubsetKey can be properly inferred on TS 4.1.5 but not on 4.2.3 (we tried migrating to 4.2.2 locally and this broke so the change in behavior is somewhere between 4.1.5 and 4.2.2)

🙂 Expected behavior

MyFavoriteFruitsSubsetKey should be properly inferred on both versions. Could be we're doing a thing we shouldn't be doing in the first place, but it's strange that it only kind of breaks and doesn't completely break.

Reacted by Val Kharitonov

Activity

  1. MartinJohns commented on Mar 11, 2021

    @MartinJohns
    Martin Johns (MartinJohns)
    on Mar 11, 2021
    Contributor
    More actions

    You forgot to fill out the issue template. 🤔

  2. robertf224 commented on Mar 11, 2021

    @robertf224
    Robert Fidler (robertf224)
    on Mar 11, 2021
    Author
    More actions

    ah sorry will edit

    Reacted by Martin Johns
  3. Ryan Cavanaugh (RyanCavanaugh)
    added
    Needs InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.
    on Mar 11, 2021
  4. Ryan Cavanaugh (RyanCavanaugh)
    assigned
    Anders Hejlsberg (ahejlsberg)
    on Mar 11, 2021
  5. Ryan Cavanaugh (RyanCavanaugh)
    added this to the TypeScript 4.3.1 milestone on Mar 11, 2021
  6. ahejlsberg commented on Mar 29, 2021

    @ahejlsberg
    Anders Hejlsberg (ahejlsberg)
    on Mar 29, 2021
    Member
    More actions

    This is an effect of #42284 and basically a duplicate of #42421.

    Previously, the MyFavoriteFruitsSubset type alias would resolve to the exact same type identity as FruitsSubset<"papaya" | "peach">, and when printing back types in diagnostics and quick info, that's what we'd show. Now, we create a separate type identity for MyFavoriteFruitsSubset and preserve the alias when printing back the type. In the MyFavoriteFruitsSubsetKey conditional type this means we're no longer inferring from one instantiation of the FruitsSubset<...> type alias to another (where we can just infer between the type arguments). Rather, we're performing structural type inference between two mapped types, and, because the transformation is lossy, we can't produce an inference for K.

  7. Anders Hejlsberg (ahejlsberg)
    added
    Breaking ChangeWould introduce errors in existing codeWould introduce errors in existing code
    Working as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
    and removed
    Needs InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.
    on Mar 29, 2021
  8. Anders Hejlsberg (ahejlsberg)
    removed this from the TypeScript 4.3.1 milestone on Mar 29, 2021
  9. typescript-bot commented on Mar 31, 2021

    @typescript-bot
    TypeScript Bot (typescript-bot)
    on Mar 31, 2021
    Contributor
    More actions

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

  10. TypeScript Bot (typescript-bot)
    closed this as completedon Mar 31, 2021
  11. microsoft
    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

  • @ahejlsberg
    Anders Hejlsberg (ahejlsberg)

Labels

Breaking ChangeWould introduce errors in existing codeWould introduce errors in existing codeWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe 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

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.