映射类型的交集 [英] Intersection of mapped types

查看:166
本文介绍了映射类型的交集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下内容:

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>属性的交集?或者只是一种不同的方式来根据数组中相关字符串的存在来获取一组类型的交集?

Is there a way to get an intersection of the properties of Pick<Properties, K>? Or just a different way to get the intersection of a set of types based on the presence of relevant strings in an array?

推荐答案

没有简单的类型运算符,例如,它可以将联合变成交集,或者允许您

There's no straightforward type operator which, say, turns a union into an intersection, or allows you to iterate union types and do stuff programmatically with the pieces. So on the face of it you're stuck.

备份,如果允许您自己从片段中构建Properties而不是试图将片段分开,则可以执行以下操作:

Backing up, if you allow yourself to build Properties from pieces instead of trying to break the pieces apart, you can do this:

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.)

You can see how each key in OuterProperties is a mapping to a key in InnerProperties. (Note that in your Properties, each outer property had a single inner property. You aren't restricted to that, though. If you wanted, say, the "foo" outer key to correspond to something with multiple inner properties like {n: number, r: RegExp} then you would add r: RegExp to InnerProperties and put foo: "n"|"r" in OuterProperties.)

现在,您可以像这样选择部分属性:

Now you can pick out partial properties like this:

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()的输出类型.我们仍然必须根据InnerPropertiesOuterProperties来定义Properties,如下所示:

So PickProps<"foo"> is {n: number}, and PickProps<"bar"> is {s: string}, and PickProps<"baz"> is {b: boolean}. And notice that PickProps<"foo"|"bar"> is {n: number; s: string}, so we have the output type of retrieveValues() ready. We still have to define Properties in terms of InnerProperties and OuterProperties, like this:

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

最后,您可以按照自己的方式声明该函数:

And finally you can declare that function the way you want it:

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

这样行得通.希望对您有所帮助.祝你好运!

So that works. Hope that's helpful. Good luck!

这篇关于映射类型的交集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆