为什么我不能将数据分配给记录?Playground link

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

推荐答案

当您使用初始值设定项声明变量时,类型脚本必须从其初始值设定项中 Select 该变量的类型为infer.并且有许多可能的类型与任何给定的初始值设定项兼容.例如,给定:

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] };

编译器必须挑选一个.多么?它使用了heuristics个适合广泛用途的产品.在这种情况下,结果是:

/* const json: {
    1: (string | number)[];
    2: (string | number)[];
} */

您可以看到,数组文字["", 1]被推断为具有类型(string | number)[],这是一个任意长度的无序可变数组,其中每个元素可以是一个字符串或一个数字.如果您想像修改json[1][2] = 3那样修改数组,您会很满意的.

但不幸的是,您想要later使用json作为MyRecord.由于json的类型不可赋给它,所以它失败了.在推断变量的类型时,编译器不会考虑将来的使用.(试想一下,这样做的编译器执行起来会有多糟糕.)任何比{1: (string | number)[]; 2: (string | number)[]}更具体的信息(编译器将初始化式设置为json)已经被丢弃了.


另一方面,当你写下这句话时:

const success: MyRecord = { 1: ["", 1], 2: ["", 2] };

(与上面的json1相同)它起作用了.这是因为编译器不再需要infer变量的类型.它只需根据类型判断初始值设定项.因此,它对照MyRecord判断初始值设定项,并发现它满足定义.换句话说,这是因为它使用变量类型来分析初始值设定项,而不是使用初始值设定项来分析变量.

Playground lik to code

Typescript相关问答推荐

如何将绑定到实例的类方法复制到类型脚本中的普通对象?

如何基于对象关键字派生类型?

处理API响应中的日期对象

如何正确地对类型脚本泛型进行限制

类型脚本类型字段组合

带占位符的模板文字类型何时扩展另一个?

对于合并对象中的可选属性(例如选项),类型推断可能是错误的

TypeScrip原始字符串没有方法

如何判断对象是否有重叠的叶子并产生有用的错误消息

是否有一个版本的联合类型递归地使属性只出现在一个可选选项中?

等待用户在Angular 函数中输入

从子类构造函数推断父类泛型类型

使用泛型识别对象值类型

类型推断对React.ForwardRef()的引用参数无效

在TypeScript中扩展重载方法时出现问题

接受字符串或数字的排序函数

如何为特定参数定义子路由?

类型脚本中参数为`T`和`t|unfined`的重载函数

我的类型谓词函数不能像我预期的那样工作.需要帮助了解原因

如何使用动态生成的键和值定义对象的形状?