返回值的断言函数?

Tho*_*mas 14 typescript

我正在尝试创建一个这样的函数:

function assert<T>(condition: T, msg?: string): T & asserts condition {
  if (!condition) {
    throw new Error(msg)
  }
  return condition
}

Run Code Online (Sandbox Code Playgroud)

目标是回归condition未修改的值,保留其类型,但也通知编译器返回的值是真实的。这将允许它用作独立语句,但也可以在表达式中不引人注目地使用:

const success: bool = true
// ... some code that might set success = false
assert(success)

const element: HTMLElement = assert(document.getElementById('foo'))
Run Code Online (Sandbox Code Playgroud)

不幸的是,上面的语法不起作用( playground)。有没有办法用 TypeScript 来表达这一点?

除了断言函数之外,我找不到任何关于断言函数的官方文档除了TypeScript 3.7 的发行说明,而这些文档仅演示了隐式返回的断言函数void

我能想到的最好的方法是仅针对对象类型的解决方法,因为它们永远不会是错误的:

function assert<T extends object>(condition: T | null | undefined, msg?: string): T {
  if (!condition) {
    throw new Error(msg)
  }
  return condition
}
Run Code Online (Sandbox Code Playgroud)

Sti*_*itt 11

问:断言函数有返回值吗?

\n

答:不可能

\n

很难找到,因为它在文档中没有明确显示,但我们确实有权威来源明确指出断言函数隐式返回void,所以答案是否定的,断言函数不能返回值。

\n

权威来源

\n
Typescript Github:PR #32695 控制流分析中的断言
\n
\n

断言返回类型谓词意味着返回值是 void 类型,并且没有规定返回其他类型的值。

\n
\n

安德斯·海尔斯伯格

\n

(这是直接从马口中得知的;Anders Hejlsberg 编写了代码,所以他知道!)

\n
Typescript 问题跟踪器:#34636 ReturnType 对断言的支持
\n
\n

根据介绍此功能的 PR,这是设计使然:

\n
\n

当以下情况时,函数调用被分析为断言调用或永不返回调用:

\n
    \n
  1. 该调用作为顶级表达式语句发生,并且
  2. \n
  3. 该调用为函数名称指定单个标识符或标识符的点分序列,并且
  4. \n
  5. 函数名称中的每个标识符都引用具有显式类型的实体,并且
  6. \n
  7. 函数名称解析为带有断言返回类型或显式从不返回类型注释的函数类型。
  8. \n
\n
\n

第一项规定调用必须作为顶级语句发生,这意味着调用不能嵌套在表达式中(例如另一个函数的参数或赋值中)。这实际上意味着,即使您可以从断言函数返回,并在可以使用返回值的位置使用它,该函数也不会被分析为断言,而是被分析为常规函数调用。因此最好隐式地说断言函数返回 void。PR 中也概述了这一点:

\n
\n

断言返回类型谓词意味着返回值是 void 类型,并且没有规定返回其他类型的值。

\n
\n
\n

提香·切尔尼科娃-德拉戈米尔

\n

(Titian 是contributorTypescript 项目的成员)

\n

社区资源

\n

社区来源的一些示例指出不能为断言函数指定返回类型。

\n
dev.to - Typescript 类型断言
\n
\n

当类型保护必须返回布尔值时,断言函数必须返回 void

\n
\n

史蒂芬·梅杰

\n
2ality.com - TypeScript:通过类型保护和断言函数缩小类型 - 5.2.2
\n
\n

5.2.2: 断言签名:断言 \xc2\xabarg\xc2\xbb 为 \xc2\xabtype\xc2\xbb

\n
function assertIsString(value: unknown): asserts value is string {\n  if (typeof value !== \'string\') {\n    throw new Error(); // assertion error\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

断言签名:断言值是字符串

\n

结果:无效,异常

\n
\n

阿克塞尔·劳施梅尔

\n

官方文档

\n

可悲的是,我在文档中找不到权威的答案......

\n
手册:缩小范围
\n

讨论类型断言,但没有具体提及断言函数

\n
备忘单:控制流分析
\n

提到断言函数。没有显示任何指定返回类型的方法,但也没有明确表示它们不能有返回类型。

\n
v3.7 发行说明:断言函数
\n

没有明确提及。但没有给出任何返回值的断言函数的示例。保护函数总是隐式返回一个真值或假值(布尔值?),并且断言函数似乎总是隐式返回void,但这里并没有直接说出来。

\n
Typescript Playground:断言函数
\n

没有演示任何返回任何内容的断言函数,但也没有明确声明这是不可能的......

\n


Cla*_*oft -2

您可以使用NonNullable<T>

function assert<T>(condition: T, msg?: string): NonNullable<T> {
  return condition ?? error(msg);
}

// workaround for https://github.com/microsoft/TypeScript/issues/18535
function error(msg?: string): never {
  throw new Error(msg);
}

const s: string | null = null;
const n: string = assert(s);
Run Code Online (Sandbox Code Playgroud)

操场