typescript - Villkorligt obligatoriska egenskaper i gränssnitt


Jag skulle vilja skriva en typ för ett objekt som kan innehålla vilken egenskap som helst, men om det har någon av egenskaperna a, b eller c, måste det innehålla alla egenskaper a, b och c.

Med andra ord: objektet kan innehålla vilken egenskap som helst, men om det innehåller a, b eller c måste det innehålla a, b och c.

let something: Something;

// these should be valid:
something = { a: 1, b: 1, c:, 1 };
something = { a: 1, b: 1, c:, 1, custom: 'custom' };
something = { custom: 'custom' };

// these should be invalid:
something = { a: 1 };
something = { a: 1, b: 1 };
something = { a: 1, c: 1 };
something = { b: 1 };
something = { a: 1, custom: 'custom' };

Hur kan detta uppnås?

Att skapa en unionstyp med ett objekt verkar korrekt, men fungerar inte:

interface RequiredProps {
    a: number;
    b: number;
    c: number;
}

type Something = RequiredProps | {};

Svar #1

Du kan skapa en unionstyp, mellan en typ som tillåter a, b, c och en indexer, och en som tvingar a, b och c att ha typen never om de är närvarande.

 type Something = ({ a: number, b: number, c: number } & { [n: string]: any }) |
    ( { a?: never, b?: never, c?: never } &{ [n: string]: any });

Om du har funktioner som returnerar never kan det vara möjligt att tilldela egenskaperna, men för de flesta praktiska fall bör detta fungera.

Vi skulle till och med kunna skapa en generisk typ för denna situation:

type RequireAll<TOptional, TRequired> = (TOptional & TRequired) | (Partial<Record<keyof TOptional, never>> & TRequired)
type Something = RequireAll<{a: number, b: number, c:number}, {[n:string]:any}>

Relaterade artiklar