任何人都可以解释为什么它会在打字稿中编译吗?
我尝试了一些谷歌搜索并在打字稿文档中查找,但没有找到答案。
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 链接
休息一会儿后,回到问题并更深入地思考,我想我明白了。
这就是 Record 在打字稿中的定义方式(来自它的源代码)
type Record<K extends keyof any, T> = {
[P in K]: T;
};
可以为此分配一个数组,因为
keyof
运算符将返回数组的索引作为键(类似于 Object.keys 的做法)。[P in K]: T
对数组有效,因为 array["0"]
是访问数组索引 0 的有效方法(array[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];