Hvorfor viser TypeScript en feil i dette scenariet med en unionstype?


I dette scenariet:

type Type = {
    a: string;
    b: string;
} | {
    a: number;
    b: number;
};

const func = ({a, b}: Type): string => {
    if (typeof a === 'string') {
        return b;
    }

    return 'w/e';
}

func({a: 1, b: 'w/e'});

Jeg får en feil på return b; som sier

Type 'string | number' kan ikke tilordnes typen 'string'.

Type 'number' kan ikke tildeles til type 'string'.

Så vidt jeg forstår av feilen, tolker Typescript typen Type som

type Type = {
    a: string | number;
    b: string | number;
};

, men selv om det er tilfelle, hvorfor kan jeg ikke kalle func-funksjonen med en streng og et tall?

Feilen på samtalen sier

Argument av typen '{ a: number; b: string; }' kan ikke tilordnes til parameter av typen 'Type'.

Type '{ a: number; b: string; }' kan ikke tilordnes typen '{ a: number; b: number; }'.

Typer av eiendom 'b' er inkompatible.

Type 'string' kan ikke tildeles typen 'number'.

(ts-versjon: 4.7.2)

Lekerom lenke

  • Rediger etter UnholySheep sitt kommentar:

Funksjonskallet med feil typer var bare for å teste hypotesen min om hvorfor jeg får den forrige feilen. Hvorfor jeg får en feil på return b; er det jeg ikke forstår.

Svar #1

Ok, svaret er Discriminated Unions. Jeg må bruke en diskriminant, en felles egenskap i hvert element av unionen. Den, diskriminant, egenskap:

  1. Må være en primitiv type, og
  2. Må ha en spesifikk verdi og ikke typen til den verdien. f.eks. isPrimary: true, ikke isPrimary: boolean.

Da kan jeg sjekke den egenskapens verdi for å anta de andre egenskapenes typer.

Også, i Typescript-versjoner < 4.6, hvis jeg har et objekt med en type spesifisert som ovenfor, hvis jeg destrukturerer det, blir de nye variablene ansett som uavhengige, og jeg vil fortsette å få en feil som ligner på det opprinnelige eksempelet. Destrukturering fungerer i versjon 4.6 eller høyere.

  • Eksempel på lekeplass (versjon 4.6)

  • Eksempel på lekeplass (versjon 4.5)

Nyttige lenker:

  • @Austaras sin lenke til Microsofts innlegg som kunngjør støtte for destrukturering
  • Forståelse av diskriminerte unioner
  • Typescripts singletons-typer

Takk @Austaras og @coglialoro

Svar #2

TS kan ikke spore forholdet mellom a og b etter at du destruerer dem, så de blir begge antatt å være string | number. TS 4.6 introduserte en begrenset kontrollflytanalyse for destruksjon, som kun gjelder diskriminerte unioner.

Relaterte artikler