如何为 TypeScript 接口强制执行多个可选属性中的至少一个?

Kau*_*ike 4 typescript

我想为可能具有属性“a”或“b”的对象声明一个接口

interface myInterface {
    a ?: string;
    b ?: string;
}
Run Code Online (Sandbox Code Playgroud)

使 a 和 b 都是可选的。我想要类似的东西

interface myInterface {
    a|b ?: string;
}
Run Code Online (Sandbox Code Playgroud)

(编辑1)扩展案例

interface myInterface 
{ 
    mustHaveProp1 : number;
    a|b : string;
    mustHaveProp2 : string;
    b|d|e : number;
}
Run Code Online (Sandbox Code Playgroud)

Tit*_*mir 5

你不能用接口来做到这一点,你可以用联合来做到这一点。这个想法是生成一个联合,其中每个联合组成部分都具有与原始类型相同的属性,但需要一个属性,因此myInterface我们需要类似:{ a: string, b?: string } | { a?: string, b: string }

上面的并集也(大部分)相当于下面的交集myInterface & ({ a : string } | { b: string }&(如果我们在和之间应用分配属性,|我们将得到(myInterface & { a: string }) | ((myInterface & { b: string }),并且由于在每个交集中,属性都显示为可选和必需的,因此必需的属性胜出)。

那么最大的问题就变成了如何从myInterface不需要明确写出来的情况下创建这个联合。为此,我们可以使用映射类型从原始类型中获取每个属性,创建每个成员组成部分,然后索引该类型以获得所有这些新类型的并集。然后我们可以与原始类型相交:

interface myInterface {
  a?: string;
  b?: string;
}

type OneProp<T> = {
  [P in keyof T]-?: Record<P, T[P]>
}[keyof T]

type RequireAtLeastOne<T> = T & OneProp<T>

let o1: RequireAtLeastOne<myInterface> = {} // err no properties
let o2: RequireAtLeastOne<myInterface> = { a: "" } // a present, ok
let o3: RequireAtLeastOne<myInterface> = { b: "" } // b present, ok
let o4: RequireAtLeastOne<myInterface> = { a: "", b: "" } // a and b present, ok
Run Code Online (Sandbox Code Playgroud)

游乐场链接