在 TS 类型推断中应对难以捉摸的 bug
2023-10-31 10:30:07
在前端开发的广阔领域中,TypeScript(TS)以其对类型安全的严谨态度而著称。它有助于防止难以捉摸的错误,使代码更加稳定可靠。然而,即使是 TS 也无法完全抵御所有类型的错误。在这里,我们将探讨一个狡猾的 TS 类型推断错误,它会让您抓耳挠腮。
情景设置
让我们考虑一个使用 await-to-js 库的场景,这是一个将异步函数转换为同步函数的实用程序。当使用此库时,我们遇到了一个奇怪的类型问题,如下所示:
import { awaitToJs } from 'await-to-js';
const [err, res] = awaitToJs(doSomethingAsync());
if (err) {
// ...
} else {
const token = res.data.token; // 类型错误:'null' 不允许
}
在这里,我们期望 TS 自动推断 res
的类型为 [null, T]
,其中 T
是 doSomethingAsync
返回类型。这意味着 res
要么为 null
(如果出现错误),要么为一个包含 token
属性的对象。但是,TS 却报了一个错误,说 res
可能为 null
,因此无法访问 token
属性。
根源挖掘
为了了解 TS 为什么会出现这种错误,我们需要深入了解它的类型推断机制。TS 使用一种称为结构性类型系统的类型系统。这意味着它将类型视为具有属性和方法的对象。在我们的情况下,res
的类型被推断为 object
,因为它来自 awaitToJs
函数,该函数返回一个对象。但是,TS 无法确定 object
类型中是否存在 token
属性,因为 object
类型可以具有任何属性。
驯服野兽
解决此类问题的一种方法是使用类型断言。类型断言告诉 TS 您确信某个变量具有特定类型,即使 TS 自身无法推断出来。在我们的示例中,我们可以使用以下断言:
if (err) {
// ...
} else {
const token = (res as { data: { token: string } }).data.token;
}
此断言明确告诉 TS,res
具有 data
属性,data
属性具有 token
属性,并且 token
的类型为 string
。这将使 TS 接受 token
变量的访问。
结论
在 TS 类型推断的世界中,有时会遇到难以捉摸的错误,这会让人感到沮丧。但是,通过了解 TS 的工作原理以及使用技巧(例如类型断言),我们可以驯服这些错误并编写出稳健可靠的代码。下次您遇到类似的问题时,请记住本文中介绍的技术,并准备好与 TS 的类型推断机制较量一番。