是否有一种简洁的功能性方法来断言集合中元素的类型?

时间:2019-02-26 01:20:05

标签: typescript

假设我们要收集页面上所有复选框的名称。

最幼稚的解决方案是

const names = [...document.querySelectorAll('input[type=checkbox]')]
    .map(el => el.name);

它不会通过类型检查,因为document.querySelectorAll返回的集合Element没有name属性。

一种解决方法是明确指定类型参数document.querySelectorAll<HTMLInputElement>

这会让编译器满意,而不是让我满意:现在,这段代码不是安全类型,可能在运行时失败。

一种类型安全的解决方案可能看起来

const names = [...document.querySelectorAll('input')]
    .filter(el => el.matches('[type=checkbox]'))
    .map(el => el.name);

但是它会使代码更冗长,更不清楚,并且通常该解决方案无法扩展(在这里我是说您不能通用地应用它,因为并非每个选择器都可以轻松拆分)。

最后,它既具有静态检查又具有运行时检查

const names = [...document.querySelectorAll('input[type=checkbox]')]
    .reduce((acc, el) => el instanceof HTMLInputElement ? [...acc, el] : acc, [] as HTMLInputElement[])
    .map(el => el.name);

这是最安全却最丑陋的

最后,我的问题是:除了让它更具可读性之外,没有其他方法可以使它安全吗?

1 个答案:

答案 0 :(得分:3)

您可以在filter中使用类型防护,以过滤掉不需要的节点并更改数组的类型:

const names = [...document.querySelectorAll('input[type=checkbox]')]
    .filter((el): el is HTMLInputElement => el instanceof HTMLInputElement)
    .map(el => el.name);