In TypeScript hat ein Promise den Typ Promise<T>, wobei T der Typ des Werts ist, mit dem es aufgelöst wird. Eine Funktion, die ein Promise zurückgibt, deklariert das in ihrem Rückgabetyp, und der Wert aus then oder await hat den Typ T.
Die Mechanik von Promises (Zustände, die Microtask-Queue, Verkettung) ist reines JavaScript und wird unter Promises in JavaScript behandelt. Auf dieser Seite geht es um die Typen.
new Promise und resolve typisieren
Ist new Promise der Rückgabewert einer Funktion mit deklariertem Rückgabetyp, kommt T von dort. Für sich allein leitet TypeScript T nicht aus den Aufrufen von resolve ab, und du bekommst Promise<unknown>. Übergib das Typargument ausdrücklich:
Zwei Details. resolve wird aus T typisiert, also ist resolve("42") in einem Promise<number> ein Compilerfehler. Und resolve() ohne Argument ist nur erlaubt, wenn T void enthält: In einem Promise<number> ist es der Fehler TS2794 (Expected 1 arguments, but got 0. Did you forget to include 'void' in your type argument to 'Promise'?).
Die Seite von reject ist nicht typisiert. Es gibt kein Promise<T, E>: Ein Promise kann mit jedem Wert abgelehnt werden.
then, catch und finally
Jedes then gibt ein neues Promise zurück, das nach dem Rückgabewert seines Callbacks typisiert ist. Gibt der Callback ein Promise zurück, packt TypeScript es aus, du bekommst also nie Promise<Promise<T>>.
Der Parameter des catch-Callbacks ist in der Standardbibliothek als any typisiert, nicht als unknown. Nichts hält dich davon ab, e.message auf einen Wert zu schreiben, der ein String sein könnte. Annotiere ihn als unknown, wie oben, und enge ihn vor der Verwendung ein. try/catch um await ist besser: Unter strict ist seine catch-Variable bereits unknown (siehe Fehlerbehandlung).
Promise.all gibt ein Tupel zurück
Bei einem Array-Literal aus Promises unterschiedlichen Typs gibt Promise.all ein Promise eines Tupels zurück, in dem jede Position ihren eigenen Typ behält:
Werte, die keine Promises sind, lassen sich untermischen und gehen unverändert durch. Promise.all wird abgelehnt, sobald eine Eingabe abgelehnt wird, und die übrigen Ergebnisse gehen verloren. Promise.race wird mit der ersten abgeschlossenen Eingabe aufgelöst oder abgelehnt und ist als Union der Eingaben typisiert; Promise.any wird mit dem ersten Erfolg aufgelöst und nur dann mit einem AggregateError abgelehnt, wenn jede Eingabe scheitert.
Promise.allSettled und sein Ergebnistyp
Promise.allSettled wartet auf jede Eingabe und wird nie abgelehnt. Jedes Ergebnis ist ein PromiseSettledResult<T>, eine Union, die du über das Feld status einengst:
r.value existiert erst nach der Prüfung von status, weil die abgelehnte Variante kein value hat. reason ist any, aus demselben Grund wie bei catch. Das filter verwendet ein Type Predicate, damit das gefilterte Array als Liste erfüllter Ergebnisse typisiert ist.
Eine Callback-API in ein Promise verpacken
Ältere APIs melden Ergebnisse über einen Callback, oft im Node-Stil (err, result) => void. Verpacke sie einmal in eine Funktion, die ein typisiertes Promise zurückgibt, dann kann der restliche Code await verwenden:
In Node erledigt util.promisify das für Funktionen, die der Konvention (err, result) folgen, und viele eingebaute Module haben bereits Promise-Versionen (node:fs/promises, node:timers/promises).
Häufige Fehler
Tzurückgeben, wo die SignaturPromise<T>sagt, oder umgekehrt. Eine nicht asynchrone Funktion, die alsPromise<User>deklariert ist, muss ein Promise zurückgeben; eineasync-Funktion gibt automatisch eines zurück.- Ein Promise nicht behandeln. Ein Aufruf wie
save(user);ohneawait,thenodercatchkompiliert problemlos, und eine Ablehnung wird zu einer Unhandled Rejection (die einen Node-Prozess standardmäßig beendet). Die Regelno-floating-promisesvon typescript-eslint findet so etwas. - Dem Typ von
.catch((e) => ...)vertrauen. Seineistany. Annotiere es alsunknown. new Promiseum etwas legen, das bereits ein Promise zurückgibt. Gib das vorhandene Promise einfach zurück oder nutzeawait.
Häufig gestellte Fragen
Was ist Promise<T> in TypeScript?
Promise<T> ist der Typ eines Promise, das mit einem Wert vom Typ T aufgelöst wird. Eine Funktion, die Promise<string> zurückgibt, liefert ein Promise, dessen then-Callback oder await einen string ergibt. Ein Promise, das ohne Wert aufgelöst wird, ist Promise<void>.
Wie typisiere ich new Promise in TypeScript?
Übergib das Typargument: new Promise<number>((resolve, reject) => ...). Ohne es kann TypeScript den Wert nicht aus den Aufrufen von resolve ableiten, und das Ergebnis ist Promise<unknown>. Für ein Promise, das ohne Wert aufgelöst wird, nimm new Promise<void>(resolve => ...), damit resolve() ohne Argument erlaubt ist.
Welchen Typ hat der Fehler im catch eines Promise?
any. Der Parameter reason des catch-Callbacks ist in der Standardbibliothek als any typisiert, weil alles geworfen oder abgelehnt werden kann. Annotiere ihn selbst als unknown (.catch((e: unknown) => ...)) und enge ihn mit instanceof Error ein, bevor du ihn verwendest.
Wie funktioniert Promise.all mit Typen in TypeScript?
Promise.all auf einem Array-Literal gibt einen Tupel-Typ mit einem Element pro Eingabe zurück, in Reihenfolge: Promise.all([getUser(), getCount()]) ist Promise<[User, number]>, also gibt Destructuring jedem Wert seinen eigenen Typ. Auf einem Array gleichen Typs, T[], gibt es Promise<T[]> zurück.
Was ist der Unterschied zwischen Promise.all und Promise.allSettled?
Promise.all wird abgelehnt, sobald eine Eingabe abgelehnt wird. Promise.allSettled wird immer aufgelöst, mit einem Array aus PromiseSettledResult<T>-Objekten: { status: "fulfilled", value } oder { status: "rejected", reason }. Prüfe status, um jedes einzuengen.