typescript - 从可区分联合数组中查找的窄返回类型
问题描述
我经常使用下面示例中的代码,并且想知道是否有一些聪明的方法可以键入find
结果而无需进行显式类型断言。
type Foo = { type: "Foo" };
type Goo = { type: "Goo" };
type Union = Foo | Goo;
const arr: Union[] = [];
const foo = arr.find(a => a.type === "Foo") as Foo;
如果as Foo
省略类型断言,Union
即使它只能返回 type ,结果也是 type Foo
。
在这样的示例中,修复类型find
以返回缩小类型的最干净的方法是什么?
编辑:这个问题也可能适用于filter
和其他类似的方法。
Edit2:建议的类似问题的接受答案(告诉 TypeScript 编译器 Array.prototype.filter 从数组中删除某些类型的方式?)表明,通过find/filter
在返回值的谓词中使用类型保护可以缩小范围。
如果例如区分字符串文字总是在键下,那么这个类型保护函数应该如何缩小任何有区别的联合type
?
解决方案
如果你想要一个用户定义的类型保护函数的生成器,它返回一个类型谓词来区分有区别的联合,它可能看起来像这样:
function discriminate<K extends PropertyKey, V extends string | number | boolean>(
discriminantKey: K, discriminantValue: V
) {
return <T extends Record<K, any>>(
obj: T & Record<K, V extends T[K] ? T[K] : V>
): obj is Extract<T, Record<K, V>> =>
obj[discriminantKey] === discriminantValue;
}
如果我调用discriminate("type", "Foo")
,结果是一个签名类似的函数<T>(obj: T)=>obj is Extract<T, {type: "Foo"}>
。(我说它是相似的,因为实际的返回值仅限T
于"type"
作为键和您可以分配"Foo"
给的值的类型。)让我们看看它是如何工作的:
const foo = arr.find(discriminate("type", "Foo")); // Foo | undefined
const goos = arr.filter(discriminate("type", "Goo")); // Goo[]
看起来不错。如果您传递不适用的字段/值,会发生以下情况:
const mistake1 = arr.find(discriminate("hype", "Foo")); // error!
// -------------------> ~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Union is not assignable to Record<"hype", any>.
const mistake2 = arr.find(discriminate("type", "Hoo")); // error!
// -------------------> ~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Union is not assignable to ((Foo | Goo) & Record<"type", "Hoo">)
好的,希望有帮助;祝你好运!
推荐阅读
- sql - 如何在sql中的一行中的每条记录的开头添加文本
- android-studio - Corei7上的颤振模拟器太慢了
- javascript - 动画属性存在时过渡不起作用
- r - 添加带有寓言预测估计的 theta 模型
- ios - AVPlayerItemDidPlayToEndTime 与 applicationDidBecomeActive 冲突
- c++ - 将数据从类的一个字段发送回类
- python - Await queue.get 卡在一个空队列上
- mongodb - 如何正确设计MongoDB集合关系
- python - 使用 QDateTimeAxis x 轴时如何向 QChart 添加点
- python - 如何使用 Pango 和 (py)Cairo 激活亚像素定位?