Skip to content

Incorrect generic inference with "inherited" types #53623

Closed

Description

Bug Report

🔎 Search Terms

Generics, inheritance, nested.

🕗 Version & Regression Information

All versions tested, up to 5.1.0-dev.

⏯ Playground Link

Playground link with relevant code

💻 Code

type ParentType<T extends number> = unknown;
type ChildType = ParentType<5>;
type GetT<T> = T extends ParentType<infer U> ? U : never; 

type Test = GetT1<ChildType1>;

🙁 Actual behavior

Type Test is equal to number rather than 5.

However, if T isn't unused in ParentType:

type ParentType<T extends number> = T;
// or
type ParentType<T extends number> = Array<T>;
...

–then Test becomes 5.

🙂 Expected behavior

Test should be 5 in all cases.

Activity

  1. fatcerberus commented on Apr 1, 2023

    @fatcerberus

    Working as intended. Inference is done by working backwards structurally. If you don’t use the type parameter then TS won’t be able to recover it through inference and you’ll just get the constraint, as you see here.

    I should note that from TS point of view any ParentType<T> is also assignable to any ParentType<U>, for all T and U. This is the nature of structural typing.

  2. fatcerberus commented on Apr 1, 2023

    @fatcerberus

    By analogy, you’re essentially asking TS to solve x * 0 = 0. You can substitute any number for x and still have a valid solution.

  3. colecrouter commented on Apr 1, 2023

    @colecrouter
    Author

    I see. Is there a way to include T in ParentType such that it does exist as a valid constraint? I can't think of a way to work around this, assuming that ParentType is actually independent of T.

    From what you're saying, it seems like passing T up through (potentially many cascading types) and including it in the base type is the only way to do this. Is that right?

  4. fatcerberus commented on Apr 1, 2023

    @fatcerberus

    If ParentType is actually independent of T then the type parameter may as well not exist. It won’t affect the type. Think of it like the type equivalent of (x: number) => 0. Once you’ve called the function, you can’t recover x - but it doesn’t really matter because the results are all interchangeable anyway.

  5. 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

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions