Skip to content

Instantiation expressions don't filter signatures with non-matching constraints #51694

Open

Description

Bug Report

🔎 Search Terms

instantiation expression, overload

🕗 Version & Regression Information

  • This is the behavior in every version I tried

⏯ Playground Link

Playground link with relevant code

💻 Code

declare function foo<T extends keyof HTMLElementTagNameMap>(arg: T): HTMLElementTagNameMap[T];
declare function foo<T extends HTMLElement>(arg: T): T;

type FirstFoo = typeof foo<"div">; // Type 'string' does not satisfy the constraint 'HTMLElement'.(2344)

🙁 Actual behavior

This instantiation expression errors despite the fact that a matching signature exists.

🙂 Expected behavior

It sounds likely that most people would assume that this should work similarly to how overloads are chosen - but instead an intersection is being created based on all signatures with the same type arguments arity.

originally reported by herjiict here

Activity

  1. fatcerberus commented on Nov 30, 2022

    @fatcerberus

    an intersection is being created based on all signatures with the same type arguments arity

    Is it that, or is it just picking the last overload, similar to what happens with Parameters?

  2. Andarist commented on Nov 30, 2022

    @Andarist
    ContributorAuthor

    IIRC what I’ve seen when debugging this - it’s an intersection, it’s not picking a single matching signature.

    I think that it makes sense per the second part of this comment: #51695 (comment) . It’s just that when mapping those signatures reportErrors was always set to true and non-matching signatures were not rejected

  3. Andarist commented on Dec 1, 2022

    @Andarist
    ContributorAuthor

    I went back to recheck the implementation, "intersection" definitely caught my eye somewhere around this code but it seems that it was in some different parts.

    So this isn't actually becoming an intersection, but the effect is kinda similar - it's an object type with multiple signatures (and more):
    https://github.dev/microsoft/TypeScript/blob/70d5cb28275d35e45a0f84aa981b45e6fb059160/src/compiler/checker.ts#L33667-L33679

  4. RyanCavanaugh commented on Dec 2, 2022

    @RyanCavanaugh
    Member
  5. apendua commented on Aug 23, 2024

    @apendua
    Contributor

    What would need to happen from the TypeScript team perspective for this change to be accepted? It seems to be a very reasonable improvement and it also addresses a couple other problems (linked above).

  6. CSharpFiasco commented on May 4, 2025

    @CSharpFiasco

    Any progress on this? Just encountered it and it'd be nice to have

  7. backbone87 commented on Oct 8, 2025

    @backbone87

    this feature does not play nicely at all with overloads:

    declare function a<T>(arg: string): string;
    declare function a<T>(arg: number): number;
    
    type A = Parameters<typeof a<unknown>>; // [arg: number]

    would expect [arg: number | string] or more likely [arg: string] | [arg: number]

    the only "filtering" behavior on signatures is based on generic arg arity:

    declare function a<T>(arg: string): string;
    declare function a<T, U>(arg: number): number;
    
    type AT = Parameters<typeof a<unknown>>; // [arg: string]
    type ATU = Parameters<typeof a<unknown, unknown>>; // [arg: number]

    in my specific case, i can use the arity "hack" (together with generic type defaults to not impede other usages that want to specify the "non-hack" type params), but it does not look very nice

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

    Experimentation NeededSomeone needs to try this out to see what happensSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions