microsoft / microsoft/TypeScript

`.then(onresolved)`'s return type should not be inferred from contextual type

Aperta
#54,551 1 commento 1 reazione 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Domain: lib.d.ts Possible Improvement
Lingua principale
Go
Stelle
111k
Fork
14.3k
Merge medio
1g 19h
PR unite (30g)
117

Descrizione

lib Update Request

Configuration Check

My compilation target is ES2015 and my lib is the default.

Also reproducible with target ESNext, ES2022 ect.

Missing / Incorrect Definition

Promise.prototype.then

Sample Code

TypeScript infers the return type of then from the contextual type information when called with only one argument.
This can cause unexpected results

let a: string | undefined
const b = a ?? await somePromise.then(() => "str")

I expect b to be string because either a is a string, somePromise resolves and then returns a string, or somePromise rejects and await throws so b is not assigned.
However b is actually string | undefined because the contextual type on the RHS of a nullish operator is the type of the LHS
and then inferred it's return type from the context because TResult2 was not inferred from arguments.

b satisfies string | undefined

I think there's actually two issues here

  • The contextual type of the RHS of nullish operator is the type of the LHS
  • .then's type definition does not use overloads for different number of arguments

The first issue seems debatable, I can understand the current behavior but these alternates make sense as well

  1. The contextual type of R should be unknown or the same as the whole L ?? R expression
  2. The contextual type of R should be NonNullable<L>

Let me know if this should be a separate issue or if there is interesting reading on the current behavior.

The next issue is caused because the return type of .then is Promise<TResult1 | TResult2> and TResult2 is not inferred from then's arguments when onrejected is not provided so it's inferred from the contextual type.

I think this issue can be fixed by changing the library to use overrides

then<TResult1>(onresolved: (t: T) => TResult1): Promise<TResult1>
then<TResult1, TResult2>(onresolved: (t: T) => TResult1, onrejected: (err: any) => TResult2): Promise<TResult1 | TResult2>
// more overrides for 0 or only onrejected args.

Documentation Link

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
https://github.com/microsoft/TypeScript/blob/main/src/lib/es5.d.ts#L1524

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia dalla definizione di Promise.prototype.then in src/lib/es5.d.ts intorno alla riga 1524 e riproduci l'esempio fornito del playground. Verifica come sono tipizzate le forme con uno e due argomenti e determina se la questione del contextual typing di nullish-operator debba essere gestita separatamente. Il lavoro è completato quando il tipo previsto della forma con un argomento è verificato senza introdurre regressioni nel comportamento documentato di Promise.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
javascript, typescript
Ambito
compilers
Tipo di issue
Bug
Difficoltà
3/5
Tempo stimato
1-2 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.