首页 > 解决方案 > 如何使用 Array.prototype.find 为联合数组匹配正确的类型?

问题描述

我有以下类型:

type A = { style: 'A', x: string }
type B = { style: 'B', y: string }

type Union = A | B;

我试图A在 a中找到 type 的元素Union[],如下所示:

const data: Union[] = [
    { style: 'A', x: 'test' },
    { style: 'B', y: 'test' },
]

const a: A | undefined = data.find(d => d.style === 'A');

但这会引发错误:

Type 'A | B | undefined' is not assignable to type 'A | undefined'.
  Property 'x' is missing in type 'B' but required in type 'A'.

的谓词函数Array.prototype.find找到正确的类型没有问题,我可以访问的属性A没有任何问题:

A型道具

是缺少细化的返回类型。


我能够解决它的唯一方法是使用 for 循环,但这感觉既麻烦又不必要。

let a: A | undefined;

for (let i = 0; i < data.length; i++) { 
    const val = data[i];
    if (val.style === 'A') { 
        a = val;
        break;
    }
}

标签: typescript

解决方案


您的谓词d => d.style === 'A'被推断为 type (d: Union) => boolean

对于您想要的行为,它必须被推断为(d: Union) => d is A,即用户定义的类型保护。这不会发生,因为 Typescript 从不推断函数是用户定义的类型保护;如果你想要它,你必须明确地将它声明为一个。如果你这样写,那么它可以工作:

function isA(d: Union): d is A {
    return d.style === 'A';
}

const a: A | undefined = data.find(isA); // no error

实际上,当我开始写这个答案时,我会说这可能是不可能的,因为它需要Array.prototype.find的返回类型取决于谓词是否是用户定义的类型保护。我不认为这是可能的,但显然它是; 我只是通过测试才发现它有效,所以我今天也学到了一些东西。

游乐场链接


推荐阅读