typescript - 键入复合类型保护 - 从类型保护推断/继承属性到其调用者
问题描述
type Bird = { fly: () => "fly" };
type Insect = { annoy: () => "annoy" };
type Dog = { beTheBest: () => "dogdogdog" };
type Animal = Bird | Insect | Dog;
const isBird = (animal: Animal): animal is Bird => {
if ("fly" in animal) return true;
return false;
};
const isInsect = (animal: Animal): animal is Insect => {
if ("annoy" in animal) return true;
return false;
};
const hasWings = (animal: Animal) => {
if (isBird(animal)) return true;
if (isInsect(animal)) return true;
return false;
};
我将两个基本的类型保护功能组合到复合hasWings
保护中,但是 TypeScript 并没有推断出它的类型保护特性——它typeof hasWings
只是简单地推断出(a: Animal) => boolean
. 有没有一种方法可以帮助 TS 推断或明确告诉它hasWings
是isInsect
和isBird
类型保护的组合,而无需手动重新指定标准?
// Something like this would be useful to me:
const hasWings = (animal: Animal): ReturnType<typeof isBird> & ReturnType<typeof isInsect> => {
if (isBird(animal)) return true;
if (isInsect(animal)) return true;
return false;
};
// Having to specify the whole list manually is not useful to me:
const hasWings = (animal: Animal): animal is Insect | Bird => {
if (isBird(animal)) return true;
if (isInsect(animal)) return true;
return false;
};
解决方案
您可以编写一个辅助函数来以这种方式组合类型保护。类型注释很拗口,但它有效:
type TypeGuard<S, T extends S> = (x: S) => x is T;
function typeGuardUnion<T extends TypeGuard<any, any>[]>(...fs: T): TypeGuard<
T extends TypeGuard<infer S, any>[] ? S : never,
T extends TypeGuard<any, infer U>[] ? U : never
> {
return ((x: any) => fs.some(f => f(x))) as any;
}
// TypeGuard<Animal, Bird | Insect>
const hasWings = typeGuardUnion(isBird, isInsect);
推荐阅读
- c++ - ifstream 只打印数组中的第一行
- r - R - 根据数据框名称中的模式在列表中绑定多个数据框
- c# - 如何将 C++ 非托管 DLL 转换为 C#
- python-3.x - 使用 Beautifulsoup 将带有 HTML 标签的字符串解析为嵌套列表
- javascript - 从内容脚本模拟放置事件时,放置事件 dataTransfer 未定义
- docker - 特使中的重定向
- ios - 如何修复自定义按钮在 SwiftUI(IOS) 中的交互?
- c# - 如何将参数从 c# 传递给 python 脚本构造函数?
- python-3.x - 不支持使用 ODBC 和 Apache Ignite 的 Python 字符串到 varchar 映射
- sql - 添加列以确保复合键是唯一的