首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类型缩小中缺少的流和类型记录中的“未知”数据类型

类型缩小中缺少的流和类型记录中的“未知”数据类型
EN

Stack Overflow用户
提问于 2020-04-27 15:51:31
回答 1查看 819关注 0票数 5

我在玩未知类型的游戏。最起码的例子是:

代码语言:javascript
复制
let value: unknown;
if (value === undefined || value === null || value === '') {
  typeof value;    //  ""|null|undefined  fine
} else if (typeof value === 'object') {
  typeof value;     // object | null  huh? 
}

这是设计上的限制还是打字稿中的错误?我在问题追踪器里找不到这样的东西。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-27 16:35:08

我将此称为设计限制/缺失特性: TypeScript目前没有减法类型否定类型,尽管在某些时候已经完成了一些工作(微软/打字稿#29317),但它是搁置。这意味着没有一种通用的方法可以采用AB两种类型来表示“所有可分配给A但不能分配给B”的类型,即k.a、A - BA \ BA & not B等。如果AB恰好是联合类型,其中B的每个成员都是D14的成员,那么您可以使用条件类型,比如Exclude,但这只适用于联合类型。

由于unknown不是一个联合类型,所以在TypeScript中无法表示unknown & not (undefined | null | "")类型,这就是您希望编译器在else子句中将value缩小到的范围。在else子句中根本不会发生收窄,而value保持unknown。抱歉的。

由于value在else子句中仍然是unknown类型,所以检查typeof value === 'object'只能缩小从unknown到typeof value === 'object'为真的类型:这是object | null。

这可能并不令人满意:为什么unknown类型被视为不统一的,而不是在内部表示为{} | null | undefined或object | string | number | boolean | null | undefined?毕竟,很难找到一个unknown类型的值,它不能分配给其他类型之一(例如,"hello"可以分配给{} )。实际上,如果将带注释的value类型更改为object | string | number | boolean | null | undefined,您将得到所需的行为:

代码语言:javascript
复制
let value: object | string | number | boolean | null | undefined;
if (value === undefined || value === null || value === '') {
    typeof value;    //  ""|null|undefined 
} else if (typeof value === 'object') {
    typeof value;     // object
}

那么,为什么unknown不一直这样做呢?与明确答案最接近的是由TS领导之一对相关问题的评论

对于我们是否需要unknown进行了长期的内部讨论,因为它有一个与{} | null | undefined相同的域--甚至建议将其作为lib.d.ts中的一个类型别名。但是我们明确地想要一种没有分布在条件类型上的类型,因为这种扩展通常会使事情变得更糟而不是更好。

将unknown作为联合对待会导致分布条件类型在下游的行为怪异。任何将类型划分为子类型联合的语言特性都具有可观察的效果,其中一些可能不是您想要看到的。我看到人们无意中发现了这样一个事实,即boolean实际上被定义为联合true | false,当人们期望它不存在时,它会分裂成碎片。总的来说,这是一件棘手的事情,任何选择都往往是一种取舍,至少会让一些人不开心。

在您的示例中,可以将带注释的value类型从unknown更改为行为更好的联合.或者,如果不能更改它,可以使用断言函数“准备”value,以便进行控制流分析:

代码语言:javascript
复制
function toUnion(
    x: unknown
): asserts x is object | string | number | boolean | null | undefined { }

然后在检查之前调用toUnion(value):

代码语言:javascript
复制
let value: unknown;
toUnion(value); // does nothing at runtime but transforms value to the union type
if (value === undefined || value === null || value === '') {
    typeof value;    //  ""|null|undefined 
} else if (typeof value === 'object') {
    typeof value;     // object
}

好吧,希望这能帮上忙,祝你好运!

操场链接到代码

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61462867

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档