跟踪类实例中的状态

2024-02-04

我想创建一个具有某些内部状态(可能是加载、错误或成功)的类。我还想在类上有一些可以检查此类状态的方法。

理想的API:

function f(x: LoadingError<number>) {
  if (x.isLoading()) {
  } else if (x.isError()) {
  } else {
    (x.data); // TypeScript knows x.data is of type `number`
  }
}

我正在努力解决的主要问题是创建isLoading and isError方法,以便 TypeScript 可以理解它们。

我尝试在实际的类结构上编写一些用户定义的类型保护(“" this is { ... }"):

class Foo {
  public value: string | null;
  public hasValue(): this is { value: string } {
    return this.value !== null;
  }
}

const foo = new Foo();
if (foo.hasValue()) {
  // OK
  foo.value.toString();
} else {
  (foo.value); // TypeScript does NOT understand that this can only be null
}

然而,这不起作用,因为 TypeScript“忘记”了类实例的状态else clause.

我的硬要求之一是使用class为此,因为我不想isLoading(instance) or isError(instance)而是方法instance.isLoading() and instance.isError().


我想创建一个具有某些内部状态的类(可能是加载、错误或成功)

创建您可能的状态类型

type State<T> = ErrorState | SuccessState<T> | LoadingState;

type ErrorState = { status: "error"; error: unknown };
type SuccessState<T> = { status: "success"; data: T };
type LoadingState = { status: "loading" };

我还想在类上有一些可以检查此类状态的方法。

创建包含状态的 Foo 类

我假设在这里,您想调用某种公共类型保护方法isSuccess, isLoading,isError它检查类实例状态,并可以通过使用 if/else 缩小 true 分支中的状态类型。您可以通过创建返回类型保护来做到这一点多态这个类型 https://www.typescriptlang.org/docs/handbook/advanced-types.html#polymorphic-this-types包含您的缩小状态的谓词。

// T is the possible data type of success state
class Foo<T = unknown> {
  constructor(public readonly currentState: State<T>) {}

  isLoading(): this is { readonly currentState: LoadingState } {
    return this.currentState.status === "loading";
  }

  isSuccess(): this is { readonly currentState: SuccessState<T> } {
    return this.currentState.status === "success";
  }

  isError(): this is { readonly currentState: ErrorState } {
    return this.currentState.status === "error";
  }
}

我们来测试一下:

const instance = new Foo({ status: "success", data: 42 });
if (instance.isSuccess()) {
  // works, (property) data: number
  instance.currentState.data; 
}

操场 https://www.typescriptlang.org/play/#code/C4TwDgpgBAysCGwIB4AqA+KBeKBRATvgPb5yLQA+sArgMa0QDOjZSamVAMkfACYCWAOwDmrCAG4AUKEh5CJMdigBvKIwTBqjAFxQARBHn494qIeL5d1QQGtBRAO6CoAXykzoMOg2Zj2S1XVELV09Rm8mRhMoXkR4XVRXd3Bobj4hUQ1oHECNEP0AGx4BET0kyUkAekqoRP5GKGAAC2gwImZ+ACMC6FiERpSoIgAzNQjmNSzJWgL4CYAxIiI0JWs7R0FMZUkoKFoiQXV8OmASAAowam7+Wih8CD4DgpA96kIIQWAxXT8MAEoVC4Krt6mkSsIzn9dM16lBYapaG97p9vlAwRlFC4VDtdncIJp8M4YYwAHSI94orIkoKaBpYemFYoZEw4oE4+peeiRSHQpqw+GvClfLI-cYsLL+LHbXF4glEvmk8nI4Xkal5OkMsJilm7NkgxgECw8xoKuENBFIj4qpC6Q0KLKubEy+5yk31MmWymqmlabCa8wkHWuSRs-aHYBw8PwQQMJSCCAOKCLIhnXLBHT6cJc5h6AA0MTiugALAAmVx-KT8UZnIRBGMQEkcsWQgHSqDVKAOEg2Rj5i7ESD4UAAvrxKCCagAW06hnZUfrHqFYhJo9MIaAA

局限性

事情是这样的:只有当你宣布你是班级成员时,你才能这样做currentState with public修饰符(TypeScript 限制)!如果你已经声明了private,您不能使用这样的类型保护来实现此目的。另一种方法是返回一个可选状态:

class Foo<T = unknown> {
... 
  getSuccess(): SuccessState<T> | null {
    return this.currentState.status === "success" ? this.currentState : null;
  }
...
}

// test it 
const instance = new Foo({ status: "success", data: 42 });
const state = instance.getSuccess()
if (state !== null) {
  // works, (property) data: number
  state.data
}

操场 https://www.typescriptlang.org/play/#code/C4TwDgpgBAysCGwIB4AqA+KBeKBRATvgPb5yLQA+sArgMa0QDOjZSamVAMkfACYCWAOwDmrCAG4AUKEh5CJMdigBvKIwTBqjAFxQARBHn494qIeL5d1QQGtBRAO6CoAXykzoMOg2Zj2S1XVELV09Rm8mRhMoXkR4XVRXd3Bobj4hUQ1oHECNEP0AGx4BET0kyUlaAvhmKAAxIiI0JWs7R0FMZUkoKFoiQXV8OmASAAowfH4AN3IofAg+foKQXupCCEFgMV0-DABKFRcKnuEIYDSS4VG93QuMxSpBagKClW6eubO152AAC35GAA6WhreabMSAoKaRjYLA4PRFdKlKAAfigfwBwNBGy2WSguieLykPSO71OWwizGuO0pLCy-kez1eXQ+n00+B+-yBIPW4KykLyMLh8PC9EiZTRGO52L5swJTOJrmOUHJBAs1LkFgeUEJzPePXm7M5mJ5YNx5AFwSFcP05hIEvRXKxvPNSHxOoV7yOpL6A2AUCEQUEDCUgggDnqjVGuStoVFPiiABoYnFdAAWABMrj2Ul96jUeJwgYQwYggPJXjFVL2kn4ADMoKModAAIQ23UHFlQAD03agDhINkYyfGxEg+FAB1iCHlAFsAEaGd7NwHT+CSI5AA

关于您的分支错误的旁注foo.hasValue():

const foo = new Foo();
if (foo.hasValue()) {
  // OK
  foo.value.toString();
} else {
  (foo.value); // TypeScript does NOT understand that this can only be null
}

TypeScript 不推断foo.value此处为 null,因为foo.hasValue()是一个自定义类型保护,只是将您的类型缩小到{ value: string }具有真实条件。如果条件为 false,则默认类型value (string | null)再次假设。自定义类型保护取消了 TypeScript 的正常分支逻辑。您可以通过简单地省略它来更改它:

if (foo.value !== null) {
  // OK
  foo.value.toString();
} else {
  (foo.value); // (property) Foo.value: null
}

操场 https://www.typescriptlang.org/play/#code/MYGwhgzhAEBiD29oG8BQ1oAcCuAjEAlsNAG5gjYCmAXNBAC4BOBAdgObQA+0L2II0ALzQARGAAmAMwgiA3Oix5CxABaQAauSoAKAJS16KgjGMpSWmnSasOAXxQKMjSvWyMW0Q8YB0ZCpWgAQkFhXn55DFtUKNRgeBYGaElEIR5KAHc4RD15AklobWT4bzUITX89XQcMAHoa6AB5AGkFIt8Lb3p4AGVrdhzo6EoQCAC0DAw2vypo1FQ8gqmLIJCePhAq8eg6xpbJxHb-Tp6+tgH7YdHqxYPpyl1ZbfrtTEZ4TEpGegBPKoRiu60MIgaJAA

如果您从类实例内部检查您的状态

class Foo<T = unknown> {
  ...
  // Define private custom type guard. We cannot use a polymorphic
  // this type on private attribute, so we pass in the state directly.
  private _isSuccess(state: State<T>): state is SuccessState<T> {
    return state.status === "success";
  }

  public doSomething() {
    // use type guard
    if (this._isSuccess(this.currentState)) {
      //...
    }

    // or inline it directly
    if (this.currentState.status === "success") {
      this.currentState.data;
      //...
    }
  }
}

操场 https://www.typescriptlang.org/play/#code/C4TwDgpgBAysCGwIB4AqA+KBeKBRATvgPb5yLQA+sArgMa0QDOjZSamVAMkfACYCWAOwDmrCAG4AUKEh5CJMdigBvKIwTBqjAFxQARBHn494qIeL5d1QQGtBRAO6CoAXykzoMOg2Zj2S1XVELV09Rm8mRhMoXkR4XVRXd3Bobj4hUQ1oHECNEP0AGx4BET0kyUlaAvhmKAAxIiI0JWs7R0FMZUkoKFoiQXV8OmASAAowfH4AN3IofAg+foKQXupCCEFgMV0-DABKFRcKnuEILYjmUb2di5Ys-ypBagKClW6eubO152AAC35GAA6WhreabMSAoKaRjYLA4MK3MoAfigfwBwNBGy2WSguieLykPSO7wA9CSoAARCAAMyE0Am01mIPURAAtqiUlBhNR4PheIDSeSAOrQWjwQT2YBQLT0ojLVkkMD-Wio-4wjxQfpQBkzJBQRDASYAI2oSAANIK1EQoA56TUYUJVdAodABPNaMBlgKejrZgB9AFeeiRdijF07e77XQuqAAmjB3yRzrvHrzTT4ZwuyF5GFw+HhBNRQmuY7a6hGgr8FW8IgwNlnf4iK5vD6x6lQUZooEBli3TtqjHrcFZPYHLqtnpdwdg7HkQGxBDF1tkwGrlMl9dkzX4WOCSuCaB-UVssC8gFat0QD3Ldf8dv99EgoezpDZ4K5uH6As+KJj9eTgcnxnCEF3gJcPhXNdWyOIlJCOIA

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

跟踪类实例中的状态 的相关文章

随机推荐

  • Isabelle/HOL 中的 primrec 和 fun 有什么区别?

    我正在阅读 Isabelle 教程 并试图澄清我对 primrec 和 fun 的使用的概念 到目前为止我搜索过的内容 包括答案here https lists cam ac uk mailman htdig cl isabelle use
  • 将 pandas 数据框显示到另一个选项卡中

    我正在尝试在另一个 输出视图 选项卡中显示我的 pandas 数据框 如此图所示 https github com quantopian qgrid blob master docs images events api gif https
  • (Oracle/SQL) 将所有数据类型合并到单个列中

    让我解释一下为什么我要这样做 我构建了一个 Tableau 仪表板 允许用户按架构 对象类型 表 视图 物化视图 等浏览 搜索仓库中的所有表和列 我想添加一个列 从每个表中的每一列中提取数据样本 这也完成了 但有这个问题 结果列由不同类型的
  • 迭代元组列表

    我正在寻找一种干净的方法来迭代元组列表 其中每个元组都是一对 如下所示 a b c d 最重要的是 我想更改列表中的元组 标准做法是避免在迭代列表的同时更改列表 那么我应该做什么 这就是我想要的 for i in range len tup
  • setTimeout 之后事件 currentTarget 发生变化

    考虑 let sel document getElementById mys sel onchange function e console log e currentTarget null false setTimeout e gt co
  • 如何使用 Eleventy 将多个 Markdown 文件合并到 Nunjucks 模板中?

    CONTEXT Eleventy 和 Nunjucks 以及 Markdown 大量长文本 使用 Markdown 更容易创建 编辑 复杂的布局 对于 SSG 来说还是新手 GOAL 使用 Markdown 管理文本内容块 将这些 Mark
  • 打印日历月

    实现打印给定月份和年份的日历的函数 首先 提示用户 Enter the month and year 一旦用户输入有效的输入 由空格分隔的两个整数 就以类似于 UNIX 输出的格式打印出日历cal命令 例如 如果用户输入03 2014 输出
  • 了解 Spark 结构化流并行性

    我是 Spark 世界的新手 正在努力解决一些概念 使用来自 Kafka 的 Spark Structured Streaming 采购时 并行性是如何发生的 让我们考虑以下代码片段 SparkSession spark SparkSess
  • AWS Lambda 中 Python 全局变量的范围

    AWS Lambda 中全局变量的范围或生命周期是多少 例如 如果我做这样的事情 cache def lambda handler event context do something with cache do something els
  • 显示我的“乘坐优步前往那里”按钮的预计到达时间和预计金额选项

    我已将 搭乘 Uber 前往那里 按钮集成到我的应用程序中 我觉得 如果我显示目的地的预计到达时间和预计价格 对用户来说会更方便 我怎样才能实现这个目标 我现在正在遵循本指南 https github com uber rides ios
  • 将 RGB 图像数组乘以标量后,使用 plt.imshow 获取黑色图

    所以我有点困惑为什么会发生这种情况 I have a binary image 现在我想将此二进制图像转换为 RGB 空间 因此我使用dstack连接第三轴的函数 Everything works fine so far but now I
  • 从数组中删除 JSON 对象会创建“未定义”对象

    我在使用 JSON 和数组时遇到一些问题 我已经摆弄 JSON 一段时间了 并尝试通过重构旧的实现来在生产中使用一些 JSON 我有两个隐藏的文本字段 一个以 1 2 3 等格式存储 id 另一个名称 name1 name2 name3 所
  • 如何在git上共享Xcode性能测试基线?

    I have performance tests on Xcode with a baseline set as shown below 这些基线似乎是本地保存的 如断点 因此我对它们的更改不会通过 git 传输 当除了我之外的任何人运行我
  • dropzone.js 使用 content-type 直接上传到 S3

    我目前正在使用 dropzone js 通过预先签名的 URL 将图像上传到 S3 一切正常 除了我无法设置正在上传的文件的内容类型 默认情况下 它们都是通过以下方式上传的binary octet stream我无法直接在浏览器中查看它们
  • 从 github 安装/运行 gradle 插件(特别是 arquilian 插件)的正确方法?

    我想在这里使用 arquillian 插件来运行 jetty 8 https github com aslakknutsen arquillian gradle plugin https github com aslakknutsen ar
  • 詹金斯即将关闭

    有时会发生奇怪的事情 詹金斯开始显示 詹金斯将关闭 即使没有人打开此消息并重新启动詹金斯 截屏 我有一个 精简备份 插件 该插件被配置为在备份后关闭 更改了此设置 现在工作正常 找到它有点棘手 因为这个插件不在配置系统下 而是在管理詹金斯下
  • 将字典列表转换为单独的列 pandas

    我想要一个有 1 列字典列表的 df 示例 df testData 1 MLB 2 NBA 3 NFL 分为以下内容 Number Sport 1 MLB 2 NBA 3 NFL 我尝试过以下方法 pd DataFrame df testD
  • Objective C:Posing 可以在 ios 上使用吗?

    我正在尝试为一个 ios 项目实现摆姿势 场景 在运行时定义控制器类 https stackoverflow com questions 29424934 defining class of controller at run time 我
  • PHP、SQL通过php变量限制查询

    PHP代码定义变量sqlshowvalue sqlshowvalue 5 if isset POST showmore sqlshowvalue 5 所以我连接到我的数据库 然后当我使用上面刚刚定义的变量运行下面的 SQL 查询时 resu
  • 跟踪类实例中的状态

    我想创建一个具有某些内部状态 可能是加载 错误或成功 的类 我还想在类上有一些可以检查此类状态的方法 理想的API function f x LoadingError