typescript - 打字稿交集类型和函数签名未引发预期错误
问题描述
我已经声明了以下类型:
type ExampleA = {
a: string;
}
type ExampleB = {
b: number;
}
type ExampleC = {
c: boolean;
}
type Examples = ExampleA &
ExampleB &
ExampleC;
然后我使用如下类型:
function foo(pattern: { [key: string]: string }) {
console.log(pattern);
}
const bar: Examples = { a: 'foo', b: 1, c: false };
foo(bar);
打字稿编译器在调用foo(bar)
方法时不会抛出任何错误,即使bar:Examples
变量与foo
.
为什么打字稿没有抛出任何错误?这是编译器中的错误吗?
解决方案
这样做的原因是交集类型可分配给它的基本类型。
作为交集类型,Examples
可分配给ExampleA
。ExampleA
可分配给{ [key: string]: string }
。因此,Examples
必须可赋值给函数参数类型
这可以在这段代码中显示:
const bar: Examples = { a: 'foo', b: 1, c: false };
const bar2: ExampleA = bar;
const bar3: { [key: string]: string } = bar2;
foo(bar3); //This works
foo(bar2); //Since the assignment bar3 = bar2 works, this must work, too
foo(bar); //Since the assignment bar2 = bar works, this must work, too
更新
当您要维护“当 A 可分配给 B 并且 B 可分配给 C 时,A必须可分配给 C”的原则时,该行为是必然的。类型系统除了允许这些类型的赋值外别无选择。但是,将值作为参数传递给foo
.
您可以将值分配给仅共享所分配值的一部分成员的类型的变量。所以这个任务工作正常:
let item: { a: string, b: number } = { a: "Hello World!", b: 1 };
let partiallyMatchingItem: { a: string } = item;
partiallyMatchingItem
拥有比类型中实际声明的更多的属性绝对没有问题。保证是最低保证。
但是,对映射类型的分配不起作用,因为item
type 的附加成员number
:
let item = { a: "Hello World!", b: 1 };
let mappedTypeItem: { [key: string]: string } = item; //Error
所以这次的保证不是最低保证,而是绝对保证。这是非常荒谬的,当你考虑到你可以多么容易地绕过它(有意或无意地):
let item = { a: "Hello World!", b: 1 };
let partiallyMatchingItem: { a: string } = item;
let mappedTypeItem: { [key: string]: string } = partiallyMatchingItem;
或者简单地说:
let item = { a: "Hello World!", b: 1 };
let mappedTypeItem: { [key: string]: string } = item as { a: string };
这是一个等待发生的错误,尤其是当您枚举 的属性mappedTypeItem
并假设所有属性的值都是 a 时string
。
考虑到 TypeScript 中结构类型赋值的常见程度,这种绝对保证不适合类型系统通常提供的最低保证系统。
一个干净的解决方案是使“常规”类型的值不能分配给映射类型(如果需要向后兼容,您可以使用tsconfig.json
文件中的开关切换它)。至少你应该避免这种类型的赋值,因为这里提供的类型安全性很弱。
推荐阅读
- excel - 按类选择嵌套元素
- python - 如何使用 opencv 和多线程 (logitech c920) 在 python 中捕获视频
- linux - 缺少“=”。在 Debian 服务中
- python - python自动将变量传递给函数
- firebase - Flutter - Firebase - Google_Sign_In - 提供的身份验证凭据格式错误或已过期
- java - 我什么时候应该实现 `Temporal` 而不是 `TemporalUnit` 和 `TemporalField`?
- java - 在Android(Java)中将String转换为json的最佳方法?
- sql-server - Springboot使用内存数据库和MSSQL
- java - 数据收集 - 多级分类,使用哪个收集?
- java - 模拟 jooq 选择请求