首页 > 解决方案 > 如何合并接口的所有值

问题描述

我正在尝试合并接口的所有值,例如:

interface IA {
    a: string;
}
interface IB {
    b: string;
}
interface IC {
    c: string;
}
//...

interface IMap {
    "a": IA;
    "b": IB;
    "c": IC;
    //...
    "z": IZ;
}

有没有办法创建一个类型,如:

type IAll = IMap["a"] & IMap["b"] & IMap["c"] & ... & IMap["z"];

我正在尝试使用这两个:

type valueMerge<T> = T[keyof T];
type valueMerge2<T extends keyof IMap = keyof IMap> = IMap[T];

// using
let t: valueof<IMap> = null as any;
let t2: valueof2 = null as any;

但是对于每一个,类型是IA | IB | IC | ... | IZ而不是IA & IB & IC & ... & IZ

标签: typescripttypescript-typings

解决方案


这类似于关于如何以编程方式将 union 变成 intersection的问题,并且它有类似的解决方案。

通常,当您查找对象类型的所有属性时,您会得到所有属性的联合,如您所见。问题是这keyof T是属性键的并,查找键的并集会为您提供属性的并集,因为属性查找在属性键类型中是协变的......但您想要的是属性中的逆变操作键类型。(您可以在此处阅读有关协方差/逆变的更多信息,但基本上协方差意味着联合输入变为联合输出,而逆变意味着联合输入变为交叉输出)。

幸运的是,函数参数是逆变的,所以如果我们可以将你的接口映射到一个旧属性类型是函数参数的新接口,我们可以到达一个地方,这些函数类型的联合可以导致它们的参数相交。使用关键字在条件类型中进行类型推断infer可以为我们做到这一点(参见“如果从逆变位置推断出任何候选者,则推断的类型是这些候选者的交集”的行)。

这是代码:

type IntersectProperties<T> = { [K in keyof T]: (x: T[K]) => void } extends {
  [K in keyof T]: (k: infer I) => void
}
  ? I
  : never;

的属性T映射到函数参数,然后我们infer一个单一的类型I对应所有的函数参数,这将是一个交集。

让我们看看它是否有效:

type IAll = IntersectProperties<IMap>;
// type IAll = IA & IB & IC & ... & IZ

看起来挺好的。希望有帮助;祝你好运!

链接到代码


推荐阅读