Promise în TypeScript

Cod asincron și iterare TypeScript 1.7

Tipul unei valori care va fi disponibilă mai târziu; T este tipul rezultatului, nu și al erorii.

Sintaxă
const p: Promise<number> = new Promise((resolve, reject) => { ... });
p.then((valoare: number) => ...);
function f(): Promise<string> { ... }

Ce face Promise<T>

Un Promise<T> reprezintă o operație care se termină mai târziu cu o valoare de tip T (sau cu o eroare). Exemple: fetch returnează Promise<Response>, readFile din node:fs/promises returnează Promise<string> când dai codificarea. Funcțiile Promise din runtime (then, Promise.all, Promise.allSettled) sunt explicate în secțiunea JavaScript.

TypeScript urmărește tipul prin lanț: dacă în then returnezi un text, rezultatul este Promise<string>. Promise.all pe un tuple dă un tuple de rezultate cu tipurile potrivite. Când creezi un Promise cu new Promise<T>(...), scrie T explicit, altfel este dedus ca unknown.

Tipul erorii nu face parte din Promise<T>: în catch, eroarea este any (în .catch) sau unknown (în try/catch cu await, în modul strict). Pentru a scoate T dintr-un Promise există Awaited<T>.

Exemple

Exemplul 1: Promise creat manual și lanț de then

function asteapta<T>(ms: number, valoare: T): Promise<T> {
    return new Promise<T>((resolve) => setTimeout(() => resolve(valoare), ms));
}

const p: Promise<number[]> = asteapta(20, [9, 10, 8]);

p.then((note) => note.reduce((s, n) => s + n, 0) / note.length)   // Promise<number>
    .then((medie) => `Media: ${medie.toFixed(2)}`)                 // Promise<string>
    .then((text) => console.log(text));

Rezultat

Media: 9.00

Exemplul 2: Promise.all păstrează tipurile pe poziții

function asteapta<T>(ms: number, valoare: T): Promise<T> {
    return new Promise((resolve) => setTimeout(() => resolve(valoare), ms));
}

const [nume, nota, promovat] = await Promise.all([
    asteapta(30, "Ana"),
    asteapta(10, 9.5),
    asteapta(20, true),
]);   // [string, number, boolean]

console.log(nume.toUpperCase(), nota.toFixed(1), promovat ? "da" : "nu");

Rezultat

ANA 9.5 da

Exemplul 3: Promise.allSettled și erori

Rezultatele au tipul PromiseSettledResult<number>, un union cu status "fulfilled" sau "rejected".

function nota(elev: string): Promise<number> {
    return elev === "Mihai" ? Promise.reject(new Error(`nicio notă pentru ${elev}`)) : Promise.resolve(elev.length + 5);
}

const rezultate = await Promise.allSettled(["Ana", "Mihai", "Ioana"].map(nota));
for (const r of rezultate) {
    if (r.status === "fulfilled") console.log("nota", r.value);
    else console.log("eroare:", (r.reason as Error).message);
}

Rezultat

nota 8
eroare: nicio notă pentru Mihai
nota 10

Greșeli frecvente

  • Uiți await sau then și folosești Promise-ul ca valoare: const note = incarca(); note.length. tsc dă Property ‘length’ does not exist on type ‘Promise<number[]>’.
  • Scrii new Promise((resolve) => resolve(5)) fără tip. Rezultatul este Promise<unknown>; scrie new Promise<number>.

Comenzi înrudite

  • async/await cu tipuri: O funcție async returnează mereu Promise<T>; await scoate valoarea de tip T din Promise.
  • Awaited: Awaited<T> dă tipul valorii pe care o obții cu await din T, desfăcând și Promise-urile imbricate.
  • generics (<T>): Parametri de tip: o funcție sau clasă scrisă o dată, care funcționează cu orice tip și păstrează tipul exact.
  • void: Tipul returnat de funcțiile care nu întorc nicio valoare utilă, de exemplu cele care doar afișează ceva.