typescript - 为什么 TypeScript 不急切地简化愚蠢的联合类型?
问题描述
这些类型实际上是相同的,但在错误消息和语言服务帮助工具提示中表示不同。为什么?
type Obj = { a: number }
// hovering over this shows:
// type SillyObj = { a: number; } | { a: number; b: number; }
type SillyObj = { a: number } | { a: number, b: number }
declare const obj: Obj;
declare const sillyObj: SillyObj;
// but the two types are inter-assignable!
// shouldn't SillyObj's representation be simplified
// to `{ a: number }`?
let check1: Obj = sillyObj; // OK
let check2: SillyObj = obj; // OK
// this error message is just wrong
// Type '{}' is not assignable to type 'SillyObj'.
// Type '{}' is missing the following properties from type '{ a: number; b: number; }': a, b
let check3: SillyObj = {} // OK
解决方案
您正在谈论的问题称为“子类型崩溃”,如GitHub 问题引入联合类型中所述。这是弃权的一般概念的一部分,我过去曾要求对此提供更多支持。
正如您所注意到的,在检查具体类型的可分配性时,确实会发生这种崩溃。也就是说,类型A | (A & B)
和A
被编译器视为可相互分配的类型,A
而B
不是通用的。
但它不会在 quickinfo/IntelliSense 中发生,并且有一个相当令人信服的原因:过度的属性检查。TypeScript 中的对象类型通常被认为是“开放的”,因为您可以通过添加额外的属性来扩展类型。如果总是这样,那么SillyObj
将完全等同于Obj
。
开放类型的替代方案是“封闭”或“精确”类型,其中不允许对象具有额外属性。TypeScript 将“新鲜”的对象文字视为需要符合类型的封闭版本而不是正常的开放版本。那么,突然之间,SillyObj
不被认为完全等同于Obj
:
const s: SillyObj = { a: 1, b: 2 }; // okay
const o: Obj = { a: 1, b: 2 }; // error! "b" does not exist in Obj
如果SillyObj
被积极吸收/崩溃/减少到Obj
,那么过多的属性检查将阻止您分配b
属性。
现在可能有一些方法可以为您提供真正的子类型折叠和维护过多的属性检查,但是他们需要对语言中的确切类型提供一些实际支持,而且还没有。
另外,我不会确切地认为错误消息“错误”。这当然是真的:
// Type '{}' is not assignable to type 'SillyObj'.
这部分在技术上也是正确的,但是忽略了如果只添加一个a
属性,错误就会消失的细微差别:
// Type '{}' is missing the following properties from type '{ a: number; b: number; }': a, b
这是自动错误消息难以避免的后果。如果一个值不能分配给联合,那是因为它不能分配给联合的任何组成部分。错误消息可能会提到所有成分,这将非常冗长,或者它只提到一些成分,这可能会让您相信修复错误的唯一方法是使值可分配给提到的成分. 我可能会说这里的错误是“误导”,而不是“错误”。
无论如何,希望这会有所帮助。祝你好运!
推荐阅读
- mysql - MYSQL:将多行分组在一个ID下,不要合并
- javascript - 使用 JetBrains Chrome 扩展在 IntelliJ 上远程调试 javascript 不起作用
- python - 通过 USB 与 python 通信
- c# - 在 lambda 中创建 IDisposable 时没有 CA2000 错误
- json - 如何修复类型'_InternalLinkedHashMap
' 不是类型转换错误中“String”类型的子类型 - python - 删除列表中以特定后缀结尾的单词
- react-native - 新手机中的 React Native 应用程序“全屏”
- python - 复制一个 CSV 中的特定项目并将它们粘贴 n 次到另一个 CSV
- r - 使用 tidyverse 格式化按 id 分组的嵌套 data.frame
- php - 在codeigniter中哪个文件在网站加载之前首先执行?