首页 > 解决方案 > 打字稿交集类型和函数签名未引发预期错误

问题描述

我已经声明了以下类型:

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.

游乐场链接

为什么打字稿没有抛出任何错误?这是编译器中的错误吗?

标签: typescript

解决方案


这样做的原因是交集类型可分配给它的基本类型。

作为交集类型,Examples可分配给ExampleAExampleA可分配给{ [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拥有比类型中实际声明的更多的属性绝对没有问题。保证是最低保证。

但是,对映射类型的分配不起作用,因为itemtype 的附加成员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文件中的开关切换它)。至少你应该避免这种类型的赋值,因为这里提供的类型安全性很弱。


推荐阅读