TypeScript
"Discriminated Unions" w TypeScript
Bardzo często w naszych projektach możemy spotykać się z typem takim jak ten poniżej:
type Order = {
status: string; // "string" jest dość szerokim typem, a pewnie statusy zamówień są ograniczone do kilku wartości
name: string;
description?: string;
expectedDelivery?: Date; // czemu opcjonalny?
deliveredOn?: Date; // kiedy opcjonalny, a kiedy nie?
};
Ten sposób definiowania typów jest dość nieczytelny (czemu niektóre właściwości są opcjonalne?) i nieelastyczny. W takich przypadkach warto zastanowić się nad użyciem tzw. Discriminated Unions.
type Order = {
name: string;
description?: string;
} & (
| {
status: "ready"; // "expectedDelivery" i "deliveredOn" nie powinny tutaj się poajawić
}
| {
status: "inProgress";
expectedDelivery: Date; // Dostępne wtedy, gdy status jest "inProgress"
}
| {
status: "complete";
expectedDelivery: Date; // Dostępne wtedy, gdy status jest "complete"
deliveredOn: Date; // Dostępne wtedy, gdy status jest "complete"
}
);
Ten zapis może wydawać się bardziej rozwlekły, ale działa już jako prosta dokumentacja domeny, usuwa mnóstwo niejasności i pozwala pisać bardziej przejrzysty kod. Teraz TS będzie w stanie "domyśleć" się, które właściwości są wymagane w zależności od statusu zamówienia.
Rozszerzenie tego tematu można znaleźć w ciekawych artykule: How I ease the next developer reading my code