TypeScript 中的 "asserts value is type" 和 "value is type" 有什么区别?

What is the difference between "asserts value is type" and "value is type" in TypeScript?

TypeScript 具有 is 运算符,可帮助创建用于类型检查的测试函数。最近我看到这个运算符的两种不同实现,其中一种使用 asserts 关键字。

我没有在文档中找到关于这两种使用方式的区别的信息。我试了一下,如果我是对的,asserts 不会让你 return 函数中的任何东西,但除此之外我没有发现任何差异。

这是我测试的代码:

// Asserts and tests the value without returninng anything
function assertIsString(value: unknown): asserts value is string {
  if (typeof value !== "string") throw Error("value is not a string");
}

// Tests the value and returns something so it can be used for typecheck
// more explicitly
function testIsString(value: unknown): value is string {
  return typeof value === "string";
}

const string = "hello";
const number = 123;

assertIsString(string); // does nothing
assertIsString(number); // throws Error
testIsString(string); // returns true
testIsString(number); // returns false

问题:这两个用例之间还有其他区别吗?

总结:主要区别在于一个抛出而另一个必须在条件中使用。


可能抛出异常的函数 return void 被调用 assertion functions.

这些做出断言(您可能认为它是与编译器创建契约),即如果函数不抛出异常,则 return 值中的谓词将为真。从那时起(在当前范围内),谓词中的类型信息将生效。


return boolean 值的函数被调用 type predicates.

而不是潜在地抛出异常(并导致您的程序停止,除非它被捕获(参见 try...catch),这些只是 return 一个布尔值。如果布尔值为真,则对于调用谓词的其余范围(例如代码块),谓词将生效。


文档链接针对每个案例(和其他信息)提供了多个示例。这是一个演示:

TS Playground

// predicate
function exists <T>(maybe: T): maybe is NonNullable<T> {
  return maybe != null;
}

// assertion
function assertExists <T>(maybe: T): asserts maybe is NonNullable<T> {
  if (maybe == null) throw new Error(`${maybe} doesn't exist`);
}

function example1 () {
  console.log('example1 begin');
  let maybe: string | undefined;

  if (exists(maybe)) { 
    maybe; // string
  }
  else {
    maybe; // undefined
  }

  console.log('example1 end');
}

function example2 () {
  console.log('example2 begin');
  let maybe: string | undefined;

  assertExists(maybe);

  maybe; // string

  console.log('example2 end');
}

example1(); // 'example1 begin' then 'example1 end'
example2(); // only 'example2 begin', then exception is thrown: `undefined doesn't exist`