microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.16k stars 12.38k forks source link

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

Open Andarist opened 1 year ago

Andarist commented 1 year ago

Bug Report

πŸ”Ž Search Terms

instantiation expression, overload

πŸ•— Version & Regression Information

⏯ 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

fatcerberus commented 1 year ago

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?

Andarist commented 1 year ago

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: https://github.com/microsoft/TypeScript/pull/51695#discussion_r1035795803 . It’s just that when mapping those signatures reportErrors was always set to true and non-matching signatures were not rejected

Andarist commented 1 year ago

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

RyanCavanaugh commented 1 year ago

@ahejlsberg any thoughts?

apendua commented 2 weeks ago

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