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:
- Må være en primitiv type, og
- Må ha en spesifikk verdi og ikke typen til den verdien. f.eks.
isPrimary: true, ikkeisPrimary: 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.