需要四个属性中的两个

时间:2018-08-30 16:42:07

标签: typescript typescript3.0

假设您有一个类似

的界面
interface Foo {
    a?: number[];
    b?: number[];
    c?: number[];
    d?: number[];
}

是否可以声明一个可以接受两个属性(例如abac的任意组合但拒绝三个属性的类型(例如abc)?

我相信

I've made a TypeScript Playground可以说明我的期望。

type Bar =
    { a: number[]; b: number[]; } |
    { a: number[]; c: number[]; } |
    { a: number[]; d: number[]; };       

function foo(a: Bar): void {
    console.log(a);
}

foo({ a: [1, 2], d: [1, 2] });
foo({ a: [1, 2], b: [1, 2], d: [1, 2] }); // Expected failure

1 个答案:

答案 0 :(得分:3)

您可以使用两种条件类型对键进行两次迭代,并获得两个键的所有可能组合的并集。不幸的是,该解决方案不能扩展到任意数量的键(类型别名不能轻易地递归),但是您可以为特定数量的组合创建相似的类型。

interface Foo {
    a?: number[];
    b?: number[];
    c?: number[];
    d?: number[];
}

type RequireTwoHelper<T, K1 extends keyof T, K2 extends keyof T> =
    K2 extends string ? { [P in K1 | K2]-?:T[P] } : never;

type RequireTwo<T, K1 extends keyof T> =
    K1 extends string ? RequireTwoHelper<T, K1, Exclude<keyof T, K1>> : never;

type RequireTwoFoo = RequireTwo<Foo, keyof Foo>

let foo: RequireTwoFoo= { a:[], b:[] };
let foo2: RequireTwoFoo= { a:[], c:[] }
let foo3: RequireTwoFoo = { a: [], d: [] }
let foo4: RequireTwoFoo = { b: [], c: [] }
let foo5: RequireTwoFoo = { b: [], d: [] }
let foo6: RequireTwoFoo = { c: [], d: [] }

let foo7: RequireTwoFoo = { a[], c: [], d: [] } //err

Playground link