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

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

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

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

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


Below is a code-snippet pulled from a guide on writing unit tests with TypeScript.
function assertNonNullish<TValue>(
  value: TValue,
  message: string
): asserts value is NonNullable<TValue> {
  if (value === null || value === undefined) {
    throw Error(message);
  }
}
[Examples Source](https://mariusschulz.com/blog/assertion-functions-in-typescript#implementing-an-assertion-function)

我还发现断言运算符用于定义 Node.js 断言库中包含的大多数断言函数的类型。这是我的悬停小部件为断言函数 deepStrictEqual 的类型显示的内容: enter image description here

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

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

stack overflow What does the TypeScript asserts operator do?
原文答案

答案:

作者头像

Assertion functions 用于需要将值缩小到更具体的类型,并且在运行其他代码之前需要强有力地保证该类型符合您的期望。

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

TS Playground

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

如果您不将类型断言为 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);
  }
}

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

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

TS Playground

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 {
    // ...
  }
}

附言我发现使用通用断言函数并将其与如下类型谓词组合起来会更加灵活:

TS Playground

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));
}

有关断言函数的更多示例,请参阅此 Deno 标准模块: https://deno.land/std@0.132.0/testing/asserts.ts ( documentation )。 (我 contributed the assertion typing 用于名为 assertExists 的那个,就像您示例中的函数。)

相关问题