TypeScript 中的类型安全谓词函数

2024-06-19

我的目标是编写谓词函数(isNull and isUndefined例如)在 TypeScript 中满足以下条件:

  1. 可以独立使用:array.filter(isNull)
  2. 可以逻辑组合:array.filter(and(not(isNull), not(isUndefined)))
  3. 使用类型保护,因此 TypeScript 知道例如的返回类型array.filter(isNull)null[]
  4. 组合谓词可以提取到新的谓词函数中,而不会破坏类型推断:const isNotNull = not(isNull)

前两个条件很容易满足:

type Predicate = (i: any) => boolean;

const and = (p1: Predicate, p2: Predicate) =>
    (i: any) => p1(i) && p2(i);

const or = (p1: Predicate, p2: Predicate) =>
    (i: any) => p1(i) || p2(i);

const not = (p: Predicate) =>
    (i: any) => !p(i);

const isNull = (i: any) =>
    i === null;

const isUndefined = (i: any) =>
    i === undefined;

const items = [ "foo", null, 123, undefined, true ];
const filtered = items.filter(and(not(isNull), not(isUndefined)));
console.log(filtered);

但因为这里没有使用类型保护,TypeScript 假设变量filtered具有相同的类型items这是(string,number,boolean,null,undefined)[]虽然现在实际上应该是(string,number,boolean)[].

所以我添加了一些打字稿魔法:

type Diff<T, U> = T extends U ? never : T;

type Predicate<I, O extends I> = (i: I) => i is O;

const and = <I, O1 extends I, O2 extends I>(p1: Predicate<I, O1>, p2: Predicate<I, O2>) =>
    (i: I): i is (O1 & O2) => p1(i) && p2(i);

const or = <I, O1 extends I, O2 extends I>(p1: Predicate<I, O1>, p2: Predicate<I, O2>) =>
    (i: I): i is (O1 | O2) => p1(i) || p2(i);

const not = <I, O extends I>(p: Predicate<I, O>) =>
    (i: I): i is (Diff<I, O>) => !p(i);

const isNull = <I>(i: I | null): i is null =>
    i === null;

const isUndefined = <I>(i: I | undefined): i is undefined =>
    i === undefined;

现在看来有效了filtered被正确地简化为类型(string,number,boolean)[].

但是因为not(isNull)可能会经常使用我想将其提取到一个新的谓词函数中:

const isNotNull = not(isNull);

虽然这在运行时完美工作,但不幸的是它无法编译(启用严格模式的 TypeScript 3.3.3):

Argument of type '<I>(i: I | null) => i is null' is not assignable to parameter of type 'Predicate<{}, {}>'.
  Type predicate 'i is null' is not assignable to 'i is {}'.
    Type 'null' is not assignable to type '{}'.ts(2345)

所以我想在使用谓词作为数组的参数时filter方法 TypeScript 可以推断出类型I从数组中提取谓词,但是当将谓词提取到单独的函数中时,这不再有效,TypeScript 会回退到基本对象类型{}这打破了一切。

有没有办法来解决这个问题?说服 TypeScript 坚持使用泛型类型的一些技巧I而不是将其解决为{}当定义isNotNull功能?或者这是 TypeScript 的限制,目前无法完成?


刚刚在这里找到了我自己两年前的问题,并使用最新的 TypeScript 版本(4.3.5)再次尝试,问题不再存在。以下代码可以正常编译并且类型可以正确推断:

type Diff<T, U> = T extends U ? never : T;

type Predicate<I, O extends I> = (i: I) => i is O;

const and = <I, O1 extends I, O2 extends I>(p1: Predicate<I, O1>, p2: Predicate<I, O2>) =>
    (i: I): i is (O1 & O2) => p1(i) && p2(i);

const or = <I, O1 extends I, O2 extends I>(p1: Predicate<I, O1>, p2: Predicate<I, O2>) =>
    (i: I): i is (O1 | O2) => p1(i) || p2(i);

const not = <I, O extends I>(p: Predicate<I, O>) =>
    (i: I): i is (Diff<I, O>) => !p(i);

const isNull = <I>(i: I | null): i is null =>
    i === null;

const isUndefined = <I>(i: I | undefined): i is undefined =>
    i === undefined;

const isNotNull = not(isNull);
const isNotUndefined = not(isUndefined);

const items = [ "foo", null, 123, undefined, true ];
const filtered = items.filter(and(isNotNull, isNotUndefined));
console.log(filtered);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TypeScript 中的类型安全谓词函数 的相关文章

随机推荐

  • 用 pandas DataFrame 替换 mysql 数据库表中的行

    Python 版本 2 7 6 熊猫版本 0 17 1 MySQLdb 版本 1 2 5 在我的数据库中 PRODUCT 我有一张桌子 XML FEED 表 XML FEED 很大 数百万条记录 我有一个 pandas DataFrame
  • 如何从批量数据中的mysql列中删除所有非数字字符

    我想从列中删除所有非数字字符 我的数据库中有大量数据 目前我正在使用以下链接中描述的方法 http venerableagents wordpress com 2011 01 29 mysql numeric functions http
  • 字形和 bootstrap 4

    我正在尝试使用 glyphicon 中的 glyphicon 当您单击一个 glyphicon 时 它会提示您所需要做的就是添加 span class span 你想要字形的地方 但在下载它们后 我注意到它们都保存为 png 文件 有谁知道
  • `cosf`、`sinf` 等不在 `std` 中 [重复]

    这个问题在这里已经有答案了 根据这里的讨论 我有报告了一个错误 https bugs launchpad net ubuntu source gcc 8 bug 1831385给 Ubuntu 开发者 编译以下示例 C 程序时 includ
  • 找不到符号assertEquals

    我正在尝试为计算器编写第一个单元测试 但 NetBeans 说它找不到该符号assertEquals和注释 Test 我应该包括一些东西吗 我正在使用 NetBeans 7 3 1 和 W7 package calculator impor
  • PhantomJS 网页内存消耗?

    是否有一种编程方式 因为我想在运行时自动执行 方式来查看网页在通过 PhantomJs 运行时使用了多少内存 我也在使用 casperjs 如果这有帮助的话 我已经搜索了很多但没有找到任何方法 PhantomJs 使用 QtWebKit 因
  • Admob 广告无法快速显示

    您好 我正在尝试将 admob 广告添加到已使用 swift 上传到应用商店的应用程序中 我在 admob 中制作了一个应用程序并复制了 appid 和广告 id 并显示了各自的横幅广告和插页式广告 这里的问题是当我写这行时 request
  • xpath:选择中断标签之前和之后的文本节点

    考虑以下因素 混合 br and br text1 br text2 br text3 br text4 br text5 如何找到每个文本节点 我正在考虑符合 br 标签之前或之后的条件的东西 但不确定是否 br and br 在 xpa
  • 递归获取数组的键并创建下划线分隔的字符串

    现在我得到了一个包含某种信息的数组 我需要从中创建一个表 例如 Student Address StreetAddress gt Some Street StreetName gt Some Name Marks1 gt 100 Marks
  • Google Place Api:来自此 Android 客户端应用程序 com.package.name 的请求被阻止

    我在用PlaceAutocompleteFragment当我单击搜索字段 PlaceAutocompleteFragment 对话框消失时 我收到此错误 errors domain global re ason forbidden mess
  • 如何生成 JavaScript 堆栈跟踪? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 关于如何以跨浏览器的方式在 javascript 中生成堆栈跟踪有什么建议吗 较新的浏览器 Chrome 和 Firefox 公开了一个允
  • 快速查询最新记录的方法?

    我有一张这样的表 USER PLAN START DATE END DATE 1 A 20110101 NULL 1 B 20100101 20101231 2 A 20100101 20100505 在某种程度上 如果END DATE i
  • ETW、.NET 4.5 - 如何写入事件日志?

    我正在尝试了解 ETW 以及如何将其集成到高性能应用程序中 我们都知道旧的令人恐惧的 EventLog 及其非结构化 因此不是最佳的 API 现在有一个用于高性能跟踪的新奇 API ETW 它在 4 5 中以 EventSource 类的形
  • 我应该如何在 VB.NET 中进行转换?

    所有这些都相等吗 在什么情况下我应该选择其中一个而不是其他 var ToString CStr 变量 CType 变量 字符串 DirectCast 变量 字符串 编辑 来自的建议不是我自己 https stackoverflow com
  • Ansible 条带空白

    当我尝试在 nxos 设备上运行某些命令时 输出末尾有一个空格 我必须将输出与现有变量列表进行比较 末尾的空格导致比较错误 如何在字符串列表中使用 strip 函数 name Current TACACS server host befor
  • 如何在 VS Code 中为 CMake 项目设置 C/C++ IntelliSense?

    我正在尝试使用 libTooling 编写一个工具 我对其进行了设置 以便它可以使用 LLVM 文档中的示例进行编译 然而 C C IntelliSense 似乎不适用于 CMake 项目 我的工具位于
  • realloc():重新分配为 char * 上的 strcat 腾出空间时下一个大小无效 [重复]

    这个问题在这里已经有答案了 我在以下代码中收到无效内存错误 printf s n FINE 5 printf s LENGTH IS d n FINE 6 strlen buffer char realloc buffer strlen b
  • django-rest-framework - POST 请求返回“不允许使用方法\”GET\”。”

    我已经按照安装教程设置了 django rest auth 但我无法使用登录 API 端点 当我发送包含正确信息的 POST 请求时 我收到 405 状态错误 响应为 不允许方法 GET 但是 当我导航到实际 URL 并从在线表单发布它时
  • scala中的协变类型参数需要在java接口中保持不变

    我有一个看起来像这样的特征 一些进一步的信息可以在我自己提出了这个相关问题 https stackoverflow com questions 3695990 inheritance and automatic type conversio
  • TypeScript 中的类型安全谓词函数

    我的目标是编写谓词函数 isNull and isUndefined例如 在 TypeScript 中满足以下条件 可以独立使用 array filter isNull 可以逻辑组合 array filter and not isNull