Typescript async-funktion returtyp void vs Promise<void>


Finns det en skillnad mellan TypeScript void och Promise< void > typer?

Frågar eftersom jag blev förvirrad över varför detta är en giltig TypeScript?

const asyncFunc: () => void = async () => {
    await new Promise(resolve => resolve());
};

Borde inte detta vara det enda giltiga fallet?

const asyncFunc: () => Promise<void> = async () => {
    await new Promise(resolve => resolve());
};

Svar #1

Ja, det finns en skillnad

void är lite som motsatsen till any: frånvaron av att ha någon typ alls. Du kan ofta se detta som returtypen för funktioner som inte returnerar ett värde

Jag antar att Promise<void> inte kräver någon förklaring.

Varför är nu tilldelningen i frågan tillåten? För att målfunktionen (() => void) kan anropas i alla (*nästan) samma situationer som källfunktionen. Ta en titt på ett förenklat exempel:

declare let voidFunc: () => void;
declare let promiseFunc: () => Promise<void>;

voidFunc = promiseFunc; // OK
promiseFunc = voidFunc; // Error: Type 'void' is not assignable to type 'Promise<void>'

Svar #2

Detta kommer också att fungera (observera att detta inte ens är en asynkron funktion):

const asyncFunc: () => void = () => {
  return Math.random() > 0.5 ? 'hello' : 'world';
};

// OR this:
const asyncFunc2: () => void = () => {
  return { nice: 'very '};
};

Varför?? I princip kan du låta TypeScript tolka typerna själv, eller så kan du sätta en specifik typ till en konstant.

Här definierade du en konstant som heter asyncFunc, som är av typen () => void. Detta betyder att TypeScript kommer att bortse från returvärdet från funktionen när typen definieras. Tänk på det som om användaren inte förväntar sig ett värde, så att returnera ett värde fortfarande bör fungera bra och inte bryta koden.

Så, vad är typen av asyncFunc??

Om du själv definierar typen på konstanten kommer typen att vara () => void, så användaren förväntar sig inget returvärde:

Men om du låter TypeScript tolka detta själv, borde det veta det korrekta värdet. Så för funktionen som definierades ovan (utan async) blir det () => string:

Så vad ska du göra?

Specifikt i fallet där en funktion definieras som()=> void, kommer funktionen inte att kontrollera returvärdet alls och du kan returnera vad som helst (även ett löfte). Att definiera en funktion som asynkron kommer bara att omsluta returvärdet i ett löfte, vilket ()=> void-typen helt enkelt ignorerar.

Om du vill definiera en annan typ av returvärdet än den tolkade typen kan du definiera en asynkron funktion för att returnera ett specifikt löfte med en nästlad typ.

Något liknande detta för ditt exempel:

const asyncFunc: () => Promise<void> = async () => {
    await new Promise(resolve => resolve());
};

Saken är den, att detta kommer att hända automatiskt utan typdefinitionen:

Så det är ganska överflödigt. Du kan bara låta TypeScript tolka typerna om du inte vill ändra returtypen till något annat.

Så, i exemplet som kan returnera hello eller world kanske vi vill låta användaren veta att returvärdet kan vara vilken sträng som helst istället för dessa två värden. Då är det logiskt att ändra definitionen av returvärdet till något annat:

Du kan kombinera någon av dessa för att uppnå ett arbetsflöde du gillar, men var medveten om att () => void är ett slags specialfall med detta typ system (eftersom alla andra returvärden förutom void kommer att ge ett typefel.

Relaterade artiklar