typescript - Typunion kontrollerar inte för överskjutande egenskaper
låt oss föreställa oss att vi har ett objekt som antingen har egenskaperna A och B eller C, t.ex.:
const temp = {
A: 1,
B: 2,
}
eller
const temp = {
C: 3,
}
Och intuitivt ser jag denna typ som:
type T = {A: number, B: number} | {C: number};
const valid: T = {A: 1, B: 2};
const alsoValid: T = {C: 3};
// Should complain but it does not
const invalid: T = {A: 1, B: 2, C: 3};
// Also should complain
const alsoInvalid: T = {A:1, C: 3};
Men TS behandlar sådan typ som {A?: number, B?: number, C?: number} och i princip gör | fälten valfria, men jag vill att TS ska klaga på inkonsekvent typ när jag lägger till C-egenskapen till A och B
Hur kan jag uppnå den önskade typen?
Svar #1
Detta är lite av en egenhet i hur unioner fungerar tillsammans med kontroller av överflödiga egenskaper. {A:1, C: 3} är faktiskt kompatibel med {C: number} förutom vid kontroller av överflödiga egenskaper:
const o = {A:1, C: 3};
const ok: {C: number} = o; // No direct literal assignment, no excess property checks
const nok: {C: number} = { A:1, C: 3}; // Excess property checks kick in
Lekplatslänk
Och egendomligheten med kontroller av överskottsegenskaper är att för unioner tillåter den att vilken egenskap som helst från någon unionmedlem kan finnas i det tilldelade objektliteralet.
Du kan få ett fel om unionens beståndsdelar är oförenliga med varandra:
type T = {A: number, B: number} | {C: number, A?: undefined, B?: undefined };
const valid: T = {A: 1, B: 2};
const alsoValid: T = {C: 3};
// Error
const invalid: T = {A: 1, B: 2, C: 3};
//Error
const alsoInvalid: T = {A:1, C: 3};
Lekplatslänk
Du kan också använda StrictUnion härifrån om unionen har många medlemmar
type UnionKeys<T> = T extends T ? keyof T : never;
type StrictUnionHelper<T, TAll> = T extends any ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
type StrictUnion<T> = StrictUnionHelper<T, T>
type T = StrictUnion<{A: number, B: number} | {C: number }>;
const valid: T = {A: 1, B: 2};
const alsoValid: T = {C: 3};
// Error
const invalid: T = {A: 1, B: 2, C: 3};
//Error
const alsoInvalid: T = {A:1, C: 3};
Lekplatslänk
Svar #2
Jag lägger bara alltid till någon typ av union. Till exempel:
type T = { A: number, B: number, type: 'ONE' } | { C: number, type: 'TWO' };
const valid: T = { A: 1, B: 2, type: 'ONE' };
const alsoValid: T = { C: 3, type: 'TWO' };
// Should complain but it does not
const invalid: T = { A: 1, B: 2, C: 3, type: "ONE" };
// Also should complain
const alsoInvalid: T = { A: 1, C: 3, type: 'TWO' };
Målet är att ha någon gemensam egenskap
