为什么可达性分析中没有考虑Promise<never>?

问题描述 投票:0回答:2

假设我们有这个函数:

function returnNever(): never {
    throw new Error();
}

创建 IIFE 时,其后面的代码将被标记为无法访问:

(async () => {
    let b: string;
    let a0 = returnNever();
    b = ""; // Unreachable
    b.toUpperCase(); // Unreachable
})();

这按预期工作。请注意,

a0
被推断为
never
类型。

但是,如果

returnNever()
返回
Promise<never>
并等待,则行为会有所不同:

(async () => {
    let b: string;
    let a1 = await Promise.reject(); // returns Promise<never>
    b = ""; // Not unreachable?
    b.toUpperCase(); // Not unreachable?
})();

在这种情况下,

a1
也被推断为
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
})();

如果

logError
同步(通过删除所有与
await
相关的
async
logError
),则不会出现错误。另外,如果
let b: string
更改为
let b: string | undefined
,则在 try-catch 块之后
undefined
不会被删除。

似乎有理由在控制流分析的任何方面都不考虑

await
Promise<never>
返回函数。 这也可能是一个错误,但我宁愿认为我在这里遗漏了一些细节。

typescript promise async-await type-inference reachability
2个回答
0
投票
当您在 TypeScript 中等待时,

A

**Promise<never>**
被视为可能引发任何错误(包括运行时错误)的类型。因为运行时有可能会抛出错误,所以await之后的代码被认为是可达的。

为了防止意外的运行时错误,TypeScript 对

Promise<never>
类型的行为旨在更加自由和保守。尽管有时不合逻辑,但这是一个经过深思熟虑的选择,旨在解决承诺和潜在的运行时异常带来的不确定性,同时保持类型系统的健全性。


0
投票

这也可能是一个错误,但我宁愿认为我在这里遗漏了一些细节。

这确实是一个错误,有关它的 GitHub 问题(由该问题的作者报告)可以在 here 找到。截至2023年,该问题仍未解决。

© www.soinside.com 2019 - 2024. All rights reserved.