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

Relaterade artiklar