nik*_*eee 5 type-inference reachability promise async-await typescript
假设我们有这个功能:
function returnNever(): never {
throw new Error();
}
Run Code Online (Sandbox Code Playgroud)
创建IIF时,其后的代码将标记为不可访问:
(async () => {
let b: string;
let a0 = returnNever();
b = ""; // Unreachable
b.toUpperCase(); // Unreachable
})();
Run Code Online (Sandbox Code Playgroud)
这按预期工作。请注意,a0推断类型为never。
但是,如果returnNever()返回a Promise<never>并等待,则行为是不同的:
(async () => {
let b: string;
let a1 = await Promise.reject(); // returns Promise<never>
b = ""; // Not unreachable?
b.toUpperCase(); // Not unreachable?
})();
Run Code Online (Sandbox Code Playgroud)
在这种情况下,a1也被推断为type never。但是之后的代码并未标记为无法访问。为什么?
背景:最近我偶然发现了一些logError类似于以下代码的函数。它在一个catch块内使用。通过这种方式,我发现,可及性分析不仅受到可及性分析的影响,而且还受到明确分配分析的影响:
declare function fetchB(): Promise<string>;
async function logError(err: any): Promise<never> {
await fetch("/foo/...");
throw new Error(err);
}
(async () => {
let b: string;
try {
b = await fetchB(); // Promise<string>
} catch (err) {
await logError(err); // awaiting Promise<never>
}
b.toUpperCase(); // Error: "b" is used before assignment
})();
Run Code Online (Sandbox Code Playgroud)
如果logError是同步的(通过删除所有await与和有关async的logError),则没有错误。另外,如果let b: string将其更改为let b: string | undefined,undefined则在try-catch块之后不会将其删除。
它似乎有一个理由不考虑await第Promise<never>-returning功能的控制流分析的任何方面。它也可能是一个错误,但我认为我在这里缺少一些细节。
Atu*_*put -1
当您在 TypeScript 中等待 A 时, A**Promise<never>**被视为可能引发任何错误(包括运行时错误)的类型。因为运行时有可能抛出错误,所以await之后的代码被认为是可达的。
为了为意外的运行时错误做好准备,TypeScript 的Promise<never>类型行为旨在更加自由和保守。尽管有时不合逻辑,但这是一个经过深思熟虑的选择,旨在解决承诺和潜在的运行时异常带来的不确定性,同时保持类型系统的健全性。
| 归档时间: |
|
| 查看次数: |
71 次 |
| 最近记录: |