其工作原理是交集类型与其基本类型的可分配性。
作为交叉口类型,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
游乐场版 http://www.typescriptlang.org/play/index.html#src=type%20ExampleA%20%3D%20%7B%0A%20%20a%3A%20string%3B%0A%7D%0A%0Atype%20ExampleB%20%3D%20%7B%0A%20%20b%3A%20number%3B%0A%7D%0A%0Atype%20ExampleC%20%3D%20%7B%0A%20%20c%3A%20boolean%3B%0A%7D%0A%0Atype%20Examples%20%3D%20ExampleA%20%26%0A%20%20ExampleB%20%26%0A%20%20ExampleC%3B%0A%0A%0Afunction%20foo(pattern%3A%20%7B%20%5Bkey%3A%20string%5D%3A%20string%20%7D)%20%7B%0A%20%20console.log(pattern)%3B%0A%7D%0A%0Aconst%20bar%3A%20Examples%20%3D%20%7B%20a%3A%20'foo'%2C%20b%3A%201%2C%20c%3A%20false%20%7D%3B%20%0Aconst%20bar2%3A%20ExampleA%20%3D%20bar%3B%0Aconst%20bar3%3A%20%7B%20%5Bkey%3A%20string%5D%3A%20string%20%7D%20%3D%20bar2%3B%0Afoo(bar3)%3B%20%2F%2FThis%20works%0Afoo(bar2)%3B%20%2F%2FSince%20the%20assignment%20bar3%20%3D%20bar2%20works%2C%20this%20must%20work%2C%20too%0Afoo(bar)%3B%20%2F%2FSince%20the%20assignment%20bar2%20%3D%20bar%20works%2C%20this%20must%20work%2C%20too%0A%0A
UPDATE
当您想要坚持“当 A 可分配给 B 并且 B 可分配给 C 时,则 Amust可分配给 C"。类型系统除了允许此类分配之外别无选择。然而,实际上有is将值作为参数传递给的另一个问题foo
.
您可以将值分配给仅共享所分配值的部分成员的类型的变量。所以这个作业工作得很好:
let item: { a: string, b: number } = { a: "Hello World!", b: 1 };
let partiallyMatchingItem: { a: string } = item;
绝对没问题partiallyMatchingItem
具有比类型中实际声明的属性更多的属性。保证是最低保证。
然而,对映射类型的分配不起作用,因为item
类型的附加成员number
:
let item = { a: "Hello World!", b: 1 };
let mappedTypeItem: { [key: string]: string } = item; //Error
所以这次的保证是not是最低限度的保证,更是绝对的保证。当你考虑到你可以多么容易地绕过它(有意或无意)时,这是相当荒谬的:
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
并且您假设所有属性的值都是string
.
考虑到结构类型赋值在 TypeScript 中非常常见,这种绝对保证不适合类型系统通常提供的最低保证系统。
一个干净的解决方案是创建“常规”类型的值not可分配给映射类型(如果需要向后兼容性,您可以使用tsconfig.json
文件)。至少您应该避免此类分配,因为此处提供的类型安全性非常弱。