async await - Väntbar typ i TypeScript
Jag använder async/await mycket i JavaScript. Nu håller jag gradvis på att konvertera vissa delar av mina kodbaser till TypeScript.
I vissa fall accepterar mina funktioner en funktion som kommer att anropas och awaitas. Detta betyder att den antingen kan returnera ett löfte eller bara ett synkront värde. Jag har definierat typen Awaitable för detta.
type Awaitable<T> = T | Promise<T>;
async function increment(getNumber: () => Awaitable<number>): Promise<number> {
const num = await getNumber();
return num + 1;
}
Det kan kallas så här:
// logs 43
increment(() => 42).then(result => {console.log(result)})
// logs 43
increment(() => Promise.resolve(42)).then(result => {console.log(result)})
Det här fungerar. Men det är irriterande att behöva specificera Awaitable för alla mina projekt som använder async/await och TypeScript.
Jag kan verkligen inte tro att en sådan typ inte är inbyggd, men jag kunde inte hitta en. Har TypeScript en inbyggd väntbar typ?
Svar #1
Jag tror att svaret på den här frågan är: Nej, det finns ingen inbyggd typ för detta.
I lib.es5.d.ts och lib.es2015.promise.d.ts använder de T | PromiseLike<T> för de olika platser där ditt Awaitable<T> skulle vara meningsfullt, till exempel:
/**
* Represents the completion of an asynchronous operation
*/
interface Promise<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
}
Det finns inget som din Awaitable i lib.es5.d.ts där de definierar PromiseLike och Promise.
Jag skulle tro att om de hade definierat en, skulle de använda den i de definitionerna.
Sidnot: Baserat på dessa definitioner är det förmodligen vettigt att använda PromiseLike istället för Promise i din Awaitable:
type Awaitable<T> = T | PromiseLike<T>;
Svar #2
Som T.J. Crowder påpekade, är det bäst att använda PromiseLike(T) | T. Att använda PromiseLike istället för Promise tillåter objekt som följer promise-gränssnittet utan att vara en instans av den inbyggda Promise-typen.
Det finns faktiskt ingen inbyggd nyttighetstyp för detta, men ts-essentials tillhandahåller en AsyncOrSync-typ, definierad så här:
type AsyncOrSync<Type> = PromiseLike<Type> | Type;
I din funktion skulle du använda det så här:
import type { AsyncOrSync } from "ts-essentials";
async function increment(getNumber: () => AsyncOrSync<number>): Promise<number> {
const num = await getNumber();
return num + 1;
}
