Typescript 的 Record 和元组无法赋值
我为什么不能将数据分配给记录?Playground 链接
type MyRecord = Record<1|2, [string, number]> ;
const json = { 1: ["",1], 2: ["",2]};
const sucess: MyRecord = { // works
1: ["",1],
2: ["",2]
}
const fail: MyRecord = json; // error
// Type '{ 1: (string | number)[]; 2: (string | number)[]; }' is not assignable to type 'MyRecord'.
// Types of property '1' are incompatible.
// Type '(string | number)[]' is not assignable to type '[string, number]'.
// Target requires 2 element(s) but source may have fewer
答案#1
当你使用初始化器声明一个变量时,TypeScript 必须从其初始化器中推断该变量的类型。而且对于任何给定的初始化器,都有许多可能的类型是兼容的。例如,给定:
const json = { 1: ["", 1], 2: ["", 2] };
以下类型都将兼容:
const json1: MyRecord = { 1: ["", 1], 2: ["", 2] };
const json2: unknown = { 1: ["", 1], 2: ["", 2] };
const json3: Record<number, any> = { 1: ["", 1], 2: ["", 2] };
const json4: { 1: any[], 2: ["", 2] } = { 1: ["", 1], 2: ["", 2] };
const json5: MyRecord | string = { 1: ["", 1], 2: ["", 2] };
编译器必须选择一个。 怎么选择? 它使用适用于广泛用途的启发式方法。 在这种情况下,它的结果是:
/* const json: {
1: (string | number)[];
2: (string | number)[];
} */
你可以看到数组字面量 ["", 1] 被推断为类型 (string | number)[],这是一个无序的可变数组,长度可以任意,每个元素可以是字符串或数字。如果你想像 json[1][2]=3 那样修改数组,你会对此感到满意。
但不幸的是,你想要稍后将json用作MyRecord。由于json的类型不能赋值给该类型,因此会失败。编译器在推断变量类型时不会考虑未来的使用情况。(试想一个考虑未来使用的编译器会有多糟糕的性能。)编译器对json初始化器的任何比{1: (string | number)[]; 2: (string | number)[]}更具体的信息都已经被丢弃了。
另一方面,当你写这个时:
const success: MyRecord = { 1: ["", 1], 2: ["", 2] };
(与上面的json1相同) 它可以工作。那是因为编译器不再需要推断变量的类型。它只需要检查初始化器是否与类型匹配。因此,它将初始化器与MyRecord进行比较,并看到它满足定义。换句话说,这行得通是因为它使用变量类型来分析初始化器,而不是使用初始化器来分析变量。
操场像编程
