我在玩未知类型的游戏。最起码的例子是:
let value: unknown;
if (value === undefined || value === null || value === '') {
typeof value; // ""|null|undefined fine
} else if (typeof value === 'object') {
typeof value; // object | null huh?
}这是设计上的限制还是打字稿中的错误?我在问题追踪器里找不到这样的东西。
发布于 2020-04-27 16:35:08
我将此称为设计限制/缺失特性: TypeScript目前没有减法类型或否定类型,尽管在某些时候已经完成了一些工作(微软/打字稿#29317),但它是搁置。这意味着没有一种通用的方法可以采用A和B两种类型来表示“所有可分配给A但不能分配给B”的类型,即k.a、A - B或A \ B或A & not B等。如果A和B恰好是联合类型,其中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,您将得到所需的行为:
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,以便进行控制流分析:
function toUnion(
x: unknown
): asserts x is object | string | number | boolean | null | undefined { }然后在检查之前调用toUnion(value):
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
}好吧,希望这能帮上忙,祝你好运!
https://stackoverflow.com/questions/61462867
复制相似问题