我可以编写一个断言多个不变量的类型保护吗?

2024-04-12

我可以编写一个类型保护来断言一个或多个子对象一个论点?在伪代码中,它可能看起来像这样:

class C {
    a: number?;
    b: string?;

    function assertInitialized() : (this.a is number) and (this.b is string) {
        return this.a !== null && this.b !== null;
    }
}

Background: I'd commonly use a single function to check invariants of my classes; for example, assume I have a class with some nullable fields, which get asynchronously initialized.
class DbClient {
    dbUrl: string;
    dbName: string;
    dbConnection: DBConnection?;
    …
}

这个类经历了一个复杂的异步初始化过程,之后dbConnection变为非空。在 dbConnection 初始化之前,该类的用户不得调用某些方法,因此我有一个函数assertReady:

assertReady() {
    if (this.dbConnection === null) {
        throw "Connection not yet established!";
    }
}

这个功能assertReady在每个需要的函数的开头调用DbClient要完全初始化,但我仍然必须编写非空断言:

fetchRecord(k: string) {
    assertReady();
    return this.dbConnection!.makeRequest(/* some request based on k */);
}

我可以给assertReady一个签名使得!不必要?我不想通过this.dbConnection to assertReady,因为该函数通常更复杂。

我知道的唯一技巧是创建一个与当前类具有相同字段的接口,但具有不可为空的类型(没有?)。然后我可以制作一个类型保护程序来表示this is InitializedDbClient。不幸的是,这需要复制类定义的很大一部分。有没有更好的办法?


是的你可以and你在伪代码中几乎完全正确

interface A {
  a?: number;
  b?: string;

  hasAandB(): this is {a: number} & {b: string};
}

注意你的伪代码是如何的and成为一个&。确实非常接近。

当然,没有必要使用该运算符,类型路口运算符,在这种情况下,因为我们可以将其简化为

hasAandB(): this is {a: number, b: string};

但想象一下我们添加第三个属性,比如说c,它不受类型保护的影响,但我们仍然不想失去它对结果类型的贡献。

您对可组合类型防护的直觉让我们回到原点

hasAandB(): this is this & {a: number, b: string};

您可以使用这些模式做各种非常有趣且非常有用的事情。

例如,您通常可以根据对象的类型传递许多属性键,并且根据您传递的实际键,结果可以针对每个属性的持有者的交集进行类型保护。

function hasProperties<T, K1 extends keyof T, K2 extends keyof T>(
  x: Partial<T>,
  key1: K1,
  key2: K2
): x is Partial<T> & {[P in K1 | K2]: T[P]} {
  return key1 in x && key2 in x;
}


interface I {
  a: string;
  b: number;
  c: boolean;
}

declare let x: Partial<I>;

if (hasProperties(x, 'a', 'b')) {...}

事实上,这只是触及了可能性的表面。

另一个非常有趣的应用是定义任意通用和类型安全的构建器和可组合工厂。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我可以编写一个断言多个不变量的类型保护吗? 的相关文章

随机推荐

  • 设置日期选择器的默认日期格式?

    我有一个页面可以跟踪各种日期 所以我最终通过 jquery 使用 datepicker 10 200 次 我想将日期选择器的所有情况的默认设置为 yy mm dd 但我似乎不知道如何设置 我最终通过 jquery 使用 datepicker
  • 从 .txt C 读取

    我在C语言方面遇到了一些麻烦 我有一个 txt 文件 其中包含以下形式的各行 F 65 S 4 1 139 56 3704 26 和我的程序 p fopen dados txt r if p NULL printf n nNao foi p
  • 保存EditText并自动检索

    您好 我正在尝试将 EditText 小部件值保存在手机 平板电脑的内部存储器中 以便应用程序关闭或活动停止时可以自动检索它们 所有这些都可以使用保存按钮进行 小部件的值由用户输入 您应该使用共享首选项 共享首选项用于将数据存储在本地应用程
  • 以非 root 用户身份使用 libusb-1.0 访问 USB 设备

    我正在尝试以 RHEL5 上的非 root 用户身份连接 USB 设备 该设备是一个 GPIO 接口 其文档可以在http www xdimax com sub20 sub20 html http www xdimax com sub20
  • Rails c 无法在 Rails 5 中工作

    关于在 Rails 5 应用程序内的终端中使用命令 rails c 抛出的错误如下所示 我不知道这在类似问题中意味着什么 解决方案是使用弹簧停止 我也尝试过 但没有 它仍然给出相同的错误 如果有人能指出这里的错误 那就太好了 Running
  • Hibernate:如何按id升序选择最后N行? (在单个查询中)

    休眠版本 5 2 我正在尝试使用子查询来做 并使用setMaxResults int session createQuery FROM SELECT FROM tickets ORDER BY id DESC limit 3 sub ORD
  • html5 canvas 游戏 - 如何添加视网膜支持

    我正在为 iPhone 创建 HTML5 画布游戏 我想支持视网膜和非视网膜显示器 我的问题是 如何同时支持视网膜和非视网膜显示器 即 执行此操作的一般实现是什么 我是否使用 iPhone 尺寸编写游戏 然后添加视网膜支持 或者我是否创建游
  • Dynamodb - 更新对象数组中 JSON 对象的值

    以下是存储在 DynamoDb 中的示例项目对象 记录 我使用 NodeJS 和AWS DynamoDB DocumentClient访问数据库 我正在构建一个 PUT 函数来更新数组中 JSON 对象的状态 该函数将有权访问该项目的uui
  • 在 Apache 中使用 mod_rewrite 处理中文字符

    我无法找到有关使用中文字符的 Apache mod rewriting 的信息 我能找到的所有信息都与数字有关 我想重写 character php character 宠 其中字符是搜索结果 因此会有所不同 character 宠 这是我
  • 共享主机帐户中的 php.ini 配置更改

    我尝试使用 htaccess ini set 覆盖默认的 php ini 配置 但在执行脚本时配置没有得到反映 这里 PHP 安装为 fastcgi 并位于共享托管帐户中 有什么方法可以更改 php ini 设置 或者我需要将我的帐户升级到
  • Rails 2.3:如何将此 SQL 语句转换为named_scope

    弄清楚如何从这个 SQL 查询创建一个named scope 有点困难 select from foo where id NOT IN select foo id from bar AND foo category ORDER BY RAN
  • mysql如何连接两个表?

    我有两张桌子 services id client service and clients id name email 如何列出餐桌服务并汇总顾客餐桌上的顾客姓名 表中的客户服务字段有客户表中客户的id 我很感谢你现在的帮助 SELECT
  • 是否可以从maven编译grunt项目?

    我正在尝试从 Maven 中执行 grunt 任务 而不需要安装 Node js 或任何东西 这是因为我不希望 Jenkins 打包我的工件 并且我无法在那台机器上安装 Node js 我知道使用 npm 和一些命令就可以让它工作很容易 但
  • 如何使用 Java 将 JMS 消息排入 Oracle AQ 中

    我有一个队列类型为 SYS AQ JMS TEXT MESSAGE 的 Oracle AQ 我想做的是将文本从 java 应用程序插入到提到的队列中 等效的 SQL 查询是 declare r enqueue options DBMS AQ
  • Cytoscape.js 的性能和布局

    我正在测试 Cytoscape js 的渲染性能 我的图表包含大约 5000 个节点和 5000 个边 没有 x y 位置 使用 Cytoscape js 的自动布局 但欧拉布局扩展在渲染完所有节点和边后需要花费超过15秒的时间 在下次操作
  • Google Plus 登录集成错误 iOS

    您好 我正在尝试在我的 iOS 应用程序上集成 google 登录 我已按照此说明进行操作link https developers google com mobile ios getting started 这些示例工作正常 但是当我尝试
  • 谷歌的 oauth2 范围有深入研究吗?

    我正在寻找有关 google 使用 oauth 范围的一些深入的详细信息 我的云端硬盘应用程序is工作 所以我可以简单地使用范围 但是我有以下详细问题 问题 我指定了两次范围 一旦进入我的应用程序 然后也进入 API 安慰 这两个范围分别有
  • MS Graph API 中的分页

    图形API分页 https graph microsoft io en us docs concepts paging解释响应将包含一个字段 odata nextLink其中将包含一个skiptoken指向下一页内容 当我测试 API 时
  • Instagram API。 “无法到达回调 URL”

    好的 伙计们 这是设置 我正在开发一个节日网站 需要使用 Instragram API 客户希望自动从 Instagram 加载使用特定主题标签的图片 没问题 Instagram API 支持此功能以及更多功能 但是 当我尝试进行订阅 通过
  • 我可以编写一个断言多个不变量的类型保护吗?

    我可以编写一个类型保护来断言一个或多个子对象一个论点 在伪代码中 它可能看起来像这样 class C a number b string function assertInitialized this a is number and thi