typescript - 类型保护和扩展联合类型?
问题描述
我有一个对象数组,其中每个项目要么扩展,{x: method}
要么{y: method}
我想尝试将它们分开。我写了以下
export const refresh = <
N extends HasRefresh | HasRefreshWithFoo,
RefreshWithFoo extends HasRefreshWithFoo,
RefreshNormal extends HasRefresh
>(
ns: N[],
foos: Foo[]
) => {
const refreshWithFoo: RefreshWithFoo = ns.filter((n): n is RefreshWithFoo =>
n.x !== undefined
)
}
但我得到了错误
A type predicate's type must be assignable to its parameter's type.
Type 'RefreshNormal' is not assignable to type 'N'.
给定一个包含扩展 HasRefreshWithFoo 或扩展 HasRefresh 的项目的对象数组,我如何将数组与联合分开,以便我有一个只有 RefreshNormal 的数组和一个只有 RefreshWithFoo 的数组?
解决方案
您可以通过对泛型类型进行另一个抽象来缩小编译器错误。
第二个抽象负责按给定类型过滤数组。
const filterByType = <T>(arr: any[], key: keyof T): T[] =>
arr.filter(e => (<T>e)[key]) as T[];
遵循Typescript 指南中的 typeguard an instance,我们被迫指定检查转换是否有效完成的键(我们过滤的类型中的唯一键)。
所以,我们现在可以通过RefreshWithFoo
export const refresh = <
N extends HasRefresh | HasRefreshWithFoo,
RefreshWithFoo extends HasRefreshWithFoo,
RefreshNormal extends HasRefresh
>(
ns: N[],
foos: Foo[]
) => {
const refreshWithFoo: RefreshWithFoo[] = filterByType<RefreshWithFoo>(ns, `x`);
}
没有任何编译器抱怨。
好吧,我使用的是默认的tsconfig,我认为这不会与任何其他编译器配置抱怨。如果是这样,请告诉我。
编辑
在某些情况下,例如类型交叉点,您将需要多个键来检查。您可以简单地通过期望一个 params 键数组来扩展该方法并检查所有这些键,就像这样
const filterByType = <T>(arr: any[], ...keys: (keyof T)[]): T[] =>
arr.filter(e => keys.every(k => (<T>e)[k])) as T[];
希望能帮助到你。
推荐阅读
- android - 带有 ViewPager 的 Android TabLayout 在旋转时重复片段内容
- algorithm - 与肯汤普森的六度分离
- node.js - 无法在 heroku 上正确部署节点 js 应用程序
- firebase - Firebase 动态链接缩短 api 将所有(空格)%20 转换为(加号)+ 嵌入链接
- android - 如何获取 px 中的实际文本大小(不是 textSize 属性)?
- html - 屏幕尺寸更改时,响应式登录的背景图片不适合
- node.js - 预提交挂钩不起作用 | 赫斯基和 Lintstaged
- linux-kernel - Drm ERROR : drm:gen8_de_irq_handler [i915] 管道 A 上的错误故障错误 0x8000080
- node.js - TypeError:无法读取未定义的 postcss/cssloader 的属性“未加前缀”
- python - “名称或服务未知”发送电子邮件