`unknown` 类型被强制转换为 `string`,尽管 `unknown` 有官方语义

`unknown` type is coerced to `string`, despite official semantics for `unknown`

我已经阅读了关于未知类型的官方文档,但我很难真正理解它是如何工作的。

可以在文档中读到:“在未首先断言或缩小到更具体的类型之前,不允许对未知进行任何操作。”

但如果我有这个功能:

const foo = (x: unknown) => {
  return x + "3";
}

TypeScript 没问题,但是这个函数会报错,提示 x 未知:

const foo = (x: unknown) => {
  return x + 3;
}

为什么它与 x + "3" 一起使用?

如果涉及转换,例如 true + 3 或 {} + 3 以及 true + "3"。

在对 + 二进制表达式进行类型检查时,如果至少一个操作数是字符串(在本例中为 "3"),则编译器会将整个表达式推断为字符串。

摘自 checkBinaryLikeExpressionWorker (https://github.com/microsoft/TypeScript/blob/main/src/compiler/checker.ts#L32087)

中的评论

If both operands are of the Number primitive type, the result is of the Number primitive type.
If one or both operands are of the String primitive type, the result is of the String primitive type.

x + 3的情况下,“number”测试失败,最后输入表达式any,报错。

这是因为 Typescript 的设计者选择允许 未检查 许多 Javascript 的隐式强制转换,通常是因为它们太惯用了。

Suggestion: stricter operators #7989:

Currently operators like "+" are defined such that they match their semantics in JS. The below are all allowed by the compiler and produce the shown values, even with --strictNullChecks on.

  • 2 + 'a' => "2a"
  • null + 'a' => "nulla" (!)
  • 2 - null => 2

Typescript 维护者一直未解决这个问题,表明他们愿意改变这个,或者至少添加一个新的编译器严格性标志。

项目负责人 Ryan Cavanaugh 说:

Approved behavior change: under --strictNullChecks it should be an error to use a possibly-null/possibly-undefined operand in a +, -, /, *, |, &, ^, or ** expression. One exception is that string + nullable is still OK since that's very common for producing debugging strings.