我有这样的函数定义:
function example<
O extends { property: P; required: boolean },
P extends string
>(
arr: O[]
): {
[P in O["property"]]: O["required"] extends true
? string
: string | undefined;
};
example([
{ property: "hey", required: true },
{ property: "ho", required: false },
]);
它给出了以下类型:
function example<{
property: "hey";
required: true;
} | {
property: "ho";
required: false;
}, string>(arr: ({
property: "hey";
required: true;
} | {
property: "ho";
required: false;
})[]): {
hey: string | undefined;
ho: string | undefined;
}
required: true
应该表示返回的对象肯定有关联的属性,required: false
应该表示可能有也可能没有,即string | undefined
。
因此,hey
在本场景中应该就是string
,因为required
就是true
。
如果required
对于两个键都是true
,则它将它们都正确地键入为string
,但是如果其中一个键是false
,则它似乎扩大了每个键/值的类型。
可以用这种方式单独Map类型吗?
Playground示例。
1条答案
按热度按时间yduiuuwa1#
问题是
O
很可能是一个并集,因此O["property"]
和O["required"]
将是分离的不相关并集,如果O
是{ property: "hey"; required: true } | { property: "ho"; required: false }
,则O["property"]
是"hey" | "ho"
,并且O["required"]
是true | false
,并且每个并集的片段之间的任何关联都已经丢失。另一种解决问题的方法是,Map类型的属性值类型根本没有提到键类型参数
P
,因此输出不可能具有依赖于单个键的属性值类型。解决这个问题的一个方法是继续在
O["property"]
上迭代P
,但是在从O
获取required
属性之前,根据P
将O
过滤到合适的成员。我们可以使用Extract<T, U>
实用程序类型来过滤联合体,方法如下:结果是
如所期望的。
另一种解决方法是在Map类型中使用键重Map,它允许您在任何联合体上迭代类型参数,然后将键更改为联合体中每个成员的函数。
因此,我们不用在每个
property
上迭代P
,然后必须 * 找到 * 正确的required
,而是在O
的每个片段上迭代T
,然后只 * 索引 *T
,得到property
和required
,这会得到相同的输出:Playground代码链接