映射类型的交集

时间:2017-11-24 00:34:58

标签: typescript mixins

请考虑以下事项:

type Properties = {
    foo: { n: number };
    bar: { s: string };
    baz: { b: boolean };
};

declare function retrieveValues<K extends keyof Properties>(add?: K[]): Pick<Properties, K>[K];

// what happens
const x: { n: number } | { s: string } = retrieveValues(['foo', 'bar']);

// what I'm really trying to express (type error)
const y: { n: number } & { s: string } = retrieveValues(['foo', 'bar']);

有没有办法获得Pick<Properties, K>的属性的交集?或者只是根据数组中相关字符串的存在来获得一组类型的交集的不同方法?

2 个答案:

答案 0 :(得分:5)

目前只在夜间typescript@next版本中提供,但在Typescript 2.8中conditional typestype inference in conditional types将允许{ n: number } | { s: string }直接转换为{ n: number } & { s: string }

type GetKeys<U> = U extends Record<infer K, any> ? K : never

type UnionToIntersection<U extends object> = {
   [K in GetKeys<U>]: U extends Record<K, infer T> ? T : never
}

type Transformed = UnionToIntersection<{ a: string } | { b: number }>
// Transformed has type {a: string, b: number} in Typescript 2.8

这个工作的原因主要是因为条件类型是在union类型上分布的。来自conditional types pull request

  

检查类型是裸类型参数的条件类型称为分布式条件类型。分布式条件类型在实例化期间自动分布在联合类型上。例如,T extends U ? X : Y的{​​{1}}类型参数A | B | C的实例化被解析为T

根据roadmap以及之前发布的时间,应在2018年3月底左右发布Typescript 2.8。

答案 1 :(得分:3)

没有简单的类型操作符,例如,将联合转换为交集,或允许您iterate union types并以编程方式执行这些操作。所以从表面上看,你已经陷入了困境。

备份,如果你允许自己从片断构建Properties而不是试图分开碎片,你可以这样做:

type InnerProperties = {
  n: number;
  s: string;
  b: boolean;
}

type OuterProperties = {
  foo: "n";
  bar: "s";
  baz: "b";
}

您可以看到OuterProperties中的每个键如何映射到InnerProperties中的键。 (请注意,在Properties中,每个外部属性都有一个内部属性。但是,您并不局限于此。如果您想要,请说"foo"外键对应某些内容如果有{n: number, r: RegExp}这样的多个内部属性,那么您可以将r: RegExp添加到InnerProperties并将foo: "n"|"r"放入OuterProperties。)

现在你可以选择这样的部分属性:

type PickProps<P extends keyof OuterProperties = keyof OuterProperties> = {
  [K in OuterProperties[P]]: InnerProperties[K];
}

因此PickProps<"foo">{n: number}PickProps<"bar">{s: string}PickProps<"baz">{b: boolean}。请注意PickProps<"foo"|"bar">{n: number; s: string},因此我们准备好retrieveValues()的输出类型。我们仍然需要根据PropertiesInnerProperties定义OuterProperties,如下所示:

type Properties = {
  [K in keyof OuterProperties]: PickProps<K>
}

最后你可以按照你想要的方式声明这个功能:

declare function retrieveValues<K extends keyof Properties>(add?: K[]): PickProps<K>;
const y: { n: number } & { s: string } = retrieveValues(['foo', 'bar']);

这样有效。希望有所帮助。祝你好运!