所以我刚才在回答这question个问题时,我发现了一些奇怪的东西,我找不到解释.

如果我们有一个泛型函数,并且参数是可选的,并且参数的类型使用泛型,则如下所示:

function ok<T>(thing?: T) {

}

然后,当我们try 将函数内的thing缩小到只有T时,显式判断它是否未定义:

thing !== undefined ? thing : 0;
//                    ^? T & ({} | null)

然后将thing缩小到T & ({} | null).此外,当我们使用typeof时,这将缩小到预期的T.这也与If语句的行为相同.

typeof thing !== "undefined" ? thing : 0;
//                             ^? T

下面是minimal reproducible example分,上面有我提到的所有事情:

function ok<T>(thing?: T) {
    thing !== undefined ? thing : 0;
    //                    ^?

    if (thing !== undefined) {
        thing
    //  ^?
    }

    typeof thing !== "undefined" ? thing : 0;
    //                             ^?

    if (typeof thing !== "undefined") {
        thing
    //  ^?
    }
}

为何会是这样呢?这两种情况真的有我不知道的不同行为吗?这是个窃听器吗?我在为这一行为寻找一个解释.

推荐答案

这是improved intersection reduction, union compatibility, and narrowing的结果,就像microsoft/TypeScript#49119中实现的那样,并在TypeScrip4.8中发布.

某些类型保护现在将以前不可缩小的(这是一个单词吗?)类型与{} | null | undefined的过滤版本相交,{} | null | undefined的联合类型相当于the unknown type,因为空对象类型{}接受所有值exceptnullundefined(有关更多信息,请参见How to undestand relations between types any, unknown, {} and between them and other types?).

具体而言,公关提到:

  • 在与nullundefined进行相等比较的控制流分析中,泛型类型与FALSE分支中的{}{} | null{} | undefined相交.

在您的例子中,值thing从类型T | undefined开始,一旦使用相等判断从类型T | undefined中删除undefined,就会得到T & ({} | null),这比单独使用T更准确地表示了thing不可能是undefined这一事实.虽然对于您的确切示例,推理通常会阻止这一点,但没有什么可以阻止某人编写ok<string | undefined>(Math.random()<0.5 ? "abc" : undefined),因此类型T将是string | undefined,而T & ({} | null)只是string(not string & {};有关为什么以及如何不同的详细信息,请参阅PR).

另一方面,这一逻辑不适用于概念上等价的typeof thing !== "undefined"判断.我在这里看到的唯一受影响的typeof张支票是typeof xxx === "object"美元.他们是否会认为x === undefinedtypeof x === "undefined"之间的差异是错误、设计限制、故意或缺失的功能,在那里没有记录,但打印肯定是按照设计的方式运行.也许开一期新的或者至少comment about it in GitHub期是值得的?不太确定.

Typescript相关问答推荐

排序更改数组类型

如何根据数据类型动态注入组件?

Angular 17 -如何在for循环内创建一些加载?

TypeScript实用程序类型—至少需要一个属性的接口,某些指定属性除外

从typescript中的对象数组中获取对象的值作为类型'

状态更新后未触发特定元素的Reaction CSS转换

打印脚本中的动态函数重载

保护函数调用,以便深度嵌套的对象具有必须与同级属性函数cargument的类型匹配的键

专用路由组件不能从挂钩推断类型

将接口映射到交叉口类型

是否将Angular *ngFor和*ngIf迁移到新的v17语法?

在TS泛型和记录类型映射方面有问题

为什么TS条件返回要求不明确的强制转换而不是精确的强制转换?

显式推断对象为只读

为什么 Typescript 无法正确推断数组元素的类型?

可选通用映射器函数出错

对象只能使用 Typescript 中另一个对象的键

包含多个不同类构造函数的接口的正确类型?

有没有办法从不同长度的元组的联合中提取带有类型的最后一个元素?

redux-toolkit、createAsyncThunk 错误