Vaak moeten we onderscheid kunnen maken tussen Typescript-interfaces die enkele eigenschappen gemeen hebben. Neem het volgende voorbeeld:
interface Vehicle { weight: number; wheels?: number; class?: 'A' | '1' | '2' | '3';
}
In onze applicatie hebben we verschillende voertuigen. Voor vrachtwagens willen we bijvoorbeeld het gewicht en het aantal wielen bijhouden. Andere voertuigen (zoals jachten) hebben echter geen wielen, maar hebben andere attributen die we willen weten, zoals bijvoorbeeld hun klasse, wat een string is die de waarden 'A', '1', '2' of '3' kan aannemen. .
We zouden kunnen denken dat een goede configuratie er als volgt uit kan zien:
interface Truck { weight: number; wheels: number;
} interface Yatch { weight: number; class: 'A' | '1' | '2' | '3';
} export type Vehicle = Truck | Yatch;
Met deze opstelling zullen we echter een probleem hebben bij het proberen te gebruiken Vehicle
voorwerpen:
Zoals we kunnen zien, kan Typescript niet beslissen of het invoerobject a is Truck
of Yatch
, en het genereert de volgende fout:
Property 'wheels' does not exist on type 'Yatch'
Hoe kunnen we het type van het object verfijnen? Er zijn minimaal 3 alternatieven:
1. Maak een nieuwe type
eigenschap op elk van de interfaces
interface Truck { weight: number; wheels: number; type: 'truck';
} interface Yatch { weight: number; class: 'A' | '1' | '2' | '3'; type: 'yatch';
} export type Vehicle = Truck | Yatch;
Dit staat bekend als gediscrimineerde vakbonden in typoscript. Deze oplossing zou het meest geschikt zijn als onze interfaces al over de type
attribuut vooraf.
Tijdens gebruik Vehicle
objecten, nu kunnen we een schakelkast gebruiken om beide interfaces te onderscheiden:
Als we klassen gebruiken in plaats van interfaces voor onze typen, levert de volgende alternatieve syntaxis exact hetzelfde resultaat op:
class Truck { weight: number; wheels: number; readonly type = 'truck';
} class Yatch { weight: number; class: 'A' | '1' | '2' | '3'; readonly type = 'yatch';
} export type Vehicle = Truck | Yatch;
2. Gebruik typebeschermers
Type bewakers zijn functies die helpen bij het verkleinen van het type.
interface Truck { weight: number; wheels: number;
} interface Yatch { weight: number; class: 'A' | '1' | '2' | '3';
} export type Vehicle = Truck | Yatch; export function isTruck(arg: any): arg is Truck { return !!arg.weight && !!arg.wheels;
} export function isYatch(arg: any): arg is Yatch { return !!arg.weight && !!arg.class;
}
If isTruck(object)
Retourneren true
, betekent dit dat ons object inderdaad a is Truck
. We kunnen deze functies overal in onze applicatie importeren en gebruiken:
Er is echter een klein probleem met deze opstelling: we kunnen nog steeds bouwen Vehicle
voorwerpen die dat niet zijn Truck
noch Yatch
:
3. Gebruik ‘nooit’
Om dit laatste probleem op te lossen kunnen we gebruik maken van de never
type, geïntroduceerd in Typescript 2.0. Als een interface de eigenschap type heeft never
, dan kan die eigenschap niet worden gedefinieerd voor enig object dat op die interface volgt.
interface Truck { weight: number; wheels: number; class?: never;
} interface Yatch { weight: number; wheels?: never; class: 'A' | '1' | '2' | '3';
} export type Vehicle = Truck | Yatch;
Type guards werken precies zoals voorheen, maar nu kunnen we geen creaties meer maken Vehicle
objecten die tegelijkertijd beide hebben wheels
en class
eigendommen:
Zoals we kunnen zien, verkrijgen we de volgende fout:
Type 'number' is not assignable to type 'never'
Bekijk de Spaanse versie van dit bericht op mijn blog cibetrucos.com
Bron: https://www.codementor.io/davidsilvasanmartin/typescript-discriminated-unions-1jhqp24mvx