TypeScript 断言运算符有什么作用?

JΛY*_*ÐΞV 7 assert typescript

我一直在 Node.js RTE 中使用 TypeScript,并且遇到了几个类型运算符(或者至少我认为它们是这样的),但我对它们一无所知。

第一个操作符是is操作符,我能够推断出第二个操作符的目的,并且找到了相关文档;是断言运算符。我一开始以为我明白它的目的是什么,但它的行为方式与我预期的一样,我也未能及时找到有关该主题的任何完整文档,尽管我确信它存在,因为 TS 有详细记录(特别是如果您考虑 TS 开发人员必须记录的内容)。

我在哪里看到正在使用断言运算符

我已经包含了一个片段和一个类型,其中包括asserts运算符。下面的两个示例概述了我遇到asserts操作符的情况,并且没有完全理解代码,因为我未能完全理解操作符的作用asserts。


下面是从使用 TypeScript 编写单元测试的指南中提取的代码片段。
function assertNonNullish<TValue>(
  value: TValue,
  message: string
): asserts value is NonNullable<TValue> {
  if (value === null || value === undefined) {
    throw Error(message);
  }
}
Run Code Online (Sandbox Code Playgroud)
示例来源


我还发现断言运算符用于定义 Node.js 断言库中包含的大多数断言函数的类型。这是我的悬停小部件显示的断言函数deepStrictEqual类型: 在此输入图像描述


_...这是断言函数类型的代码(与图像相同,只是代码形式):
type DeepStrictEqual = <T>(actual: unknown, expected: T, message?: string | Error | undefined) => asserts actual is T;
Run Code Online (Sandbox Code Playgroud)

我真的不明白使用断言运算符的目的。我想弄清楚它与键入 JavaScript 代码以及在 TypeScript 中编写单元测试和断言函数有何关系,以便我可以更好地理解何时(以及在何处)应该使用它。

jse*_*ksn 12

当您需要将值缩小到更特定的类型,并且需要在运行其他代码之前强有力地保证该类型满足您的期望时,可以使用断言函数。

考虑以下示例,其中您从一个可能是 astring或 a 的变量开始number,并且需要将该值与仅接受 a 的函数一起使用number:

TS游乐场

function double (n: number): number {
  return n * 2;
}

function assertIsNumber (value: unknown): asserts value is number {
  if (typeof value !== 'number') throw new Error('Not a number');
}

function example (value: string | number): void {
  try {
    assertIsNumber(value);
    console.log(double(value));
  }
  catch (exception) {
    console.error(exception);
  }
}

example('hello'); // Error: Not a number
example(11); // 22

Run Code Online (Sandbox Code Playgroud)

如果您不将类型断言为 a number,则无法将其与double函数一起使用:

function example (value: string | number): void {
  try {
    console.log(double(value)); /*
                       ~~~~~
    Argument of type 'string | number' is not assignable to parameter of type 'number'.
      Type 'string' is not assignable to type 'number'.(2345) */
  }
  catch (exception) {
    console.error(exception);
  }
}
Run Code Online (Sandbox Code Playgroud)

断言函数允许您使用范围的其余部分的值,缩小到您断言它的类型。

如果您只使用了谓词函数,那么每次您想要使用该值作为缩小类型时,您都需要将代码移动到一个新块(在匹配条件内):

TS游乐场

function double (n: number): number {
  return n * 2;
}

function isNumber (value: unknown): value is number {
  return typeof value === 'number';
}

function example (value: string | number): void {
  if (isNumber(value)) {
    console.log(double(value));
  }
  else {
    // ...
  }
}

Run Code Online (Sandbox Code Playgroud)

PS我发现使用通用断言函数并将其与类型谓词组合起来可以更灵活,如下所示:

TS游乐场

function double (n: number): number {
  return n * 2;
}

function assert (expr: unknown, msg?: string): asserts expr {
  if (!expr) throw new Error(msg);
}

function isNumber (value: unknown): value is number {
  return typeof value === 'number';
}

function example (value: string | number): void {
  assert(isNumber(value), 'Not a number');
  console.log(double(value));
}

Run Code Online (Sandbox Code Playgroud)

有关断言函数的更多示例,请参阅此 Deno 标准模块:(https://deno.land/std@0.132.0/testing/asserts.ts文档)。(我为名为 的函数贡献了断言类型assertExists,这就像您示例中的函数。)