typescript Record 接受数组,为什么?

问题描述 投票:0回答:3

任何人都可以解释为什么它会在打字稿中编译吗?
我尝试了一些谷歌搜索并在打字稿文档中查找,但没有找到答案。

type RecType = Record<string, any>
const arr: RecType = [1, 2, "three"] //or new Array(1, 2, 3)

console.log(arr)  // [1, 2, "three"] 
console.log(Array.isArray(arr)) // true
console.log(Object.keys(arr)) // ["0", "1", "2"] 

这是带有代码的 typescript Playground 链接

arrays typescript record
3个回答
3
投票

休息一会儿后,回到问题并更深入地思考,我想我明白了。

这就是 Record 在打字稿中的定义方式(来自它的源代码)

type Record<K extends keyof any, T> = {
    [P in K]: T;
};

可以为此分配一个数组,因为

  • keyof
    运算符将返回数组的索引作为键(类似于 Object.keys 的做法)。
  • 访问器
    [P in K]: T
    对数组有效,因为
    array["0"]
    是访问数组索引 0 的有效方法(
    array[0]
  • 也是如此)

希望我的理解是正确的,欢迎指正。


1
投票

如果您想要一个具有未知值的实际字符串键控对象,但不允许使用数组,最好使用

Record<string, unknown>
来排除传入的数组。请参阅 TS Playground 示例


0
投票

您可能会感到惊讶,它不仅仅接受数组和对象。以下所有都是有效的作业:

const a: Record<string, any> = []; 
const b: Record<string, any> = {}; 
const c: Record<string, any> = () => {};
const d: Record<string, any> = new Map();
const e: Record<string, any> = new Date();
const f: Record<string, any> = new Boolean(); 
const g: Record<string, any> = new String();
const h: Record<string, any> = class Klass{};

当您使用

new
调用构造函数时,
instanceof Object
将返回 true:

function instanceOfObject(arg: Record<string, any>) {
    return arg instanceof Object;
}

// all true
console.log(
    instanceOfObject([]),
    instanceOfObject({}),
    instanceOfObject(() => {}),
    instanceOfObject(new Map()),
    instanceOfObject(new Date()),
    instanceOfObject(new Boolean()),
    instanceOfObject(new String()),
    instanceOfObject(class Klass{}),
)

所以,这里的

Record
只是
{ [P in string]: any; }
的昵称,意思是“有一个字符串索引签名”。实际上,我们的
instanceOfObject
函数接受任何对象/实例。

请记住,TypeScript 是结构类型的,因此它会检查对象接口并查找签名。 这里

Object
接口有字符串签名。

也许

Record
的更好名称是
Indexed
,以免与其他语言中常见但在 JavaScript 中不可用的字典混淆。

例如,我们知道数组可以通过数字索引来索引。 所以我们可以分配:

const arr: Record<number, unknown> = [1,2,3]; // OK

但你可能会再次感到惊讶:

const str: Record<number, unknown> = "whoa"; // OK

是的,即使是字符串文字“也可以分配给记录”。这是有效的,因为 string 可以按数字索引。 另请注意,文字类型在 JavaScript 中是 autoboxed,并且不是用

new
初始化,因此
instanceof
失败。

console.log("str" instanceof String) // false
console.log(new String("str") instanceof String) // true

这就是为什么我们使用

typeof
运算符(如
typeof "str" === "string"
中的文字值),并且我们不鼓励使用
String
和相关类。

因此,当您只想接受对象文字时,请使用

Record<string, unknown>
,它不允许上面的对象实例,甚至不允许数组,因为它没有字符串索引签名:

// Type 'number[]' is not assignable to type 'Record<string, unknown>'.
//  Index signature for type 'string' is missing in type 'number[]'
const obj: Record<string, unknown> = [1];
© www.soinside.com 2019 - 2024. All rights reserved.