Conditional required properties in interface

2019-07-15 17:48发布

I'd like to type an object that can contain any property, but if it has any of the properties a, b or c, it must contain all of the properies a, b and c.

In other words: the object can contain any property, but if it contains a, b or c it must contain a, b and 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' };

How can this be achieved?

Creating a union type with an object seems correct, but doesn't work:

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

type Something = RequiredProps | {};

标签: typescript
1条回答
倾城 Initia
2楼-- · 2019-07-15 18:24

You can create a union type, between a type that allows a, b, and c and an indexer, and one that forces a, b, and c if present to have type never.

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

If you have functions that returnnever it may be possible to assign the properties but for most practical casses this should work.

We could even create a generic type for this 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}>
查看更多
登录 后发表回答