microsoft / microsoft/TypeScript
Counterexample to current ReturnType logic with type parameters
Nessuno ha ancora preso questa issue.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.4k
- Merge medio
- 1g 19h
- PR unite (30g)
- 117
Descrizione
🔎 Search Terms
"ReturnType inference any"
🕗 Version & Regression Information
This is the behavior in every version I tried
⏯ Playground Link
💻 Code
type T0 = ReturnType<<T>(t: T) => keyof T>; // any
type ExpectedReturnType = keyof unknown; // never
🙁 Actual behavior
ReturnType fails and returns any
🙂 Expected behavior
Given the fact that the upper bound of the type parameter T is unknown, I'd expect keyof unknown as result, i.e. never.
Additional information about the issue
This is somewhat related to #55667 and it comes from the attempts made to understand why #55714 failed to pass all the test cases.
We have:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
The problem seems to be located in compareSignaturesRelated, called by getConditionalType to resolve the ReturnType's inner conditional type. We have that source = <T>(t: T): keyof T is compared against target = (...args: any): never. This never is, in fact, the correct return type R that was successfully inferred.
Because source has a type parameter, instantiateSignatureInContextOf(source, target, ...) comes into play and we get a new source: (t: any): string | number | symbol. I'm not 100% sure about the logic of instantiateSignatureInContextOf, but it's worth noting that target is the second argument of the call above and the type of target's parameter is any. Therefore it seems that, from the source point of view, T becomes just any (and keyof any is exactly string | number | symbol).
We now have source = (t: any): string | number | symbol to be compared against target = (...args: any): never. This comparison fails because of the return types: string | number | symbol is not assignable to never, thus the assignability check also fails and we get the falseType as result, i.e. any.
The example in this issue may seem intentionally crafted, and in fact it is, but the point was to highlight the same problem explained by this comment. There we have a similar issue with the source we get from instantiateSignatureInContextOf: any has been substituted with never inside ReturnType definition, therefore if source has a type parameter it will be instantiated with never and sometimes things don't end well.
This probably undermines the possibility of having an all-encompassing definition for ReturnType if we use a concrete type for the arguments. However you type the rest parameter inside it, I suppose you can always find a counterexample that uses a not-yet-instantiated type parameter to make the assignability check of the conditional fail.
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia con la definizione condizionale di ReturnType e l’esempio del playground, poi segui getConditionalType, compareSignaturesRelated e instantiateSignatureInContextOf. Analizza come viene istanziato il parametro di tipo durante il confronto delle signature. Il lavoro è completato quando l’esempio si risolve in keyof unknown (never) senza regressioni nei casi correlati di ReturnType.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- typescript
- Ambito
- compilers
- Tipo di issue
- Bug
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Ferma
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 25/100