typescript - Am un tip care este uniunea a două interfețe care diferă printr-o proprietate, de ce TS nu poate recunoaște când omiteți o proprietate comună și o adăugați înapoi?
Iată terenul de joacă Typescript cu codul pentru această întrebare, care este de asemenea mai jos.
În esență
enum Color {
Red = "RED",
Orange = "ORANGE"
}
enum Package {
Single = "SINGLE",
Multiple = "MULTIPLE"
}
export interface ShipmentSingle {
id: string;
color: Color,
package: Package.Single
}
export interface ShipmentMultiple {
id: string;
color: Color,
package: Package.Multiple,
quantity: number
}
type Shipment = ShipmentSingle | ShipmentMultiple
const s: Shipment = {
id: '1',
color: Color.Red,
package: Package.Single
}
const addIdToOrder = (shipment: Omit<Shipment, 'id'>): Shipment => ({
...shipment,
id: '2'
})
Văd eroarea
Tipul '{ id: string; color: Color; package: Package; }' nu poate fi atribuit tipului 'Shipment'. Proprietatea 'quantity' lipsește în tipul '{ id: string; color: Color; package: Package; }', dar este necesară în tipul 'ShipmentMultiple'.
De ce este asta?
Răspuns #1
Eroarea apare deoarece Omit folosește intern keyof T. keyof T, atunci când este aplicat unui tip de uniune (Shipment este tip de uniune), returnează doar cheile care există în ambele tipuri din care constă uniunea.
type Keys = keyof Shipment; // Keys = 'id' | 'color' | 'package'.
Motivul pentru aceasta este descris aici.
Deci Omit<Shipment, 'id'> produce un obiect cu proprietățile color și package. quantity nu există.
Pentru a rezolva această problemă, aș putea recomanda să folosiți tipuri condiționale distributive pentru a distribui mai întâi Shipment către ShipmentSingle și ShipmentMultiple, apoi să aplicați Omit fiecăruia dintre ele. Astfel, rezultatul va fi din nou un tip de uniune.
type OmitWithDistribution<T, K extends keyof T> = T extends any ? Omit<T, K> : never;
const addIdToOrder = (shipment: OmitWithDistribution<Shipment, 'id'>): Shipment => ({
...shipment,
id: '2'
})
