typescript - 记录之间的区别和 [key: string]: 类型
问题描述
我想知道 和 之间的Record<key, type>
区别[key: string]: type
。我们可以互换使用它们吗?哪个更动态和类型安全?
我有一个例子,我可以互换使用它们。使用哪一个是好的做法?
//Record example
interface PageInfo {
title: string;
}
type Page = "home" | "about" | "contact";
const nav: Record<Page, PageInfo> = {
about: { title: "about" },
contact: { title: "contact" },
home: { title: "home" },
};
console.log(nav.about);
// object example
type Page2 = {
[key: string]: PageInfo;
};
const navHtml: Page2 = {
about: { title: "about" },
contact: { title: "contact" },
home: { title: "home" },
};
console.log(navHtml.contact);
解决方案
首先,AFAIK,它们都不是完全类型安全的。
看到这个问题
key
您可以在 Record -中使用联合类型Record<Page, PageInfo>
,而在索引类型中则不能:
type Page2 = {
[key: string | number | symbol]: PageInfo; // error
};
例子
//Record example
interface PageInfo {
title: string;
}
type Page = "home" | "about" | "contact";
const nav: Record<Page, PageInfo> = {
about: { title: "about" },
contact: { title: "contact" },
home: { title: "home" },
};
console.log(nav.about);
// object example
type Page2 = {
[key: string]: PageInfo;
};
const navHtml: Page2 = {
about: { title: "about" },
contact: { title: "contact" },
home: { title: "home" },
};
console.log(navHtml.contact);
/**
* If you have a string as a key - no problem
*/
type Test1 = Record<string, string> extends { [p: string]: string } ? true : false // true
type Test2 = { [p: string]: string } extends Record<string, string> ? true : false // true
const foo = (arg: Record<string, string>) => arg
const indexed: { [p: string]: string } = { bar: 'bar' }
foo(indexed) // no error
/**
* And vice-versa
*/
const bar = (arg: { [p: string]: string }) => arg
const record: Record<string, string> = { bar: 'bar' }
foo(record) // no error
/**
* But if you have a union type as a key
* Above approach will not work
*/
type Test3 = Record<'a' | 'b', string> extends { [p: string]: string } ? true : false // true
type Test4 = { [p: string]: string } extends Record<'a' | 'b', string> ? true : false // false
const withIndex: Record<'a' | 'b', string> = { bar: 'bar' } // missing a,b
更新
/**
* Explanation of Record<'a'|'b', string>
* It is mean that objects should have a & b keys
*/
type CustomRecord = Record<'a' | 'b', string>
const allowedRecord: CustomRecord = {
a: '1',
b: '2'
} // ok
const allowedRecord2: CustomRecord = {
a: '1',
} // error, because without b
const allowedRecord3: CustomRecord = {
b: '1',
} // error, because without a
/**
* You are unable to do same thing with indexed type
*/
type TypeIndexedWIthExplicitKeys = {
[p: string | number]: string
}
interface InterfaceIndexedWIthExplicitKeys {
[p: 'a' | 'b']: string
}
const x: InterfaceIndexedWIthExplicitKeys = { 2: 's' } // no error, but.... I would expect an error
const y: TypeIndexedWIthExplicitKeys = { 2: 's' } // no error, but.... I would expect an error
const check = (): InterfaceIndexedWIthExplicitKeys => {
return { 2: 2 } // no error, but I would expect
}
type MyRecord = Record<'a' | 'b', string>
const z: MyRecord = { 2: '2' } // error, because we expect a & b
const c: MyRecord = { a: '2', b: '3' } // ok
推荐阅读
- javascript - 试图理解 Javascript 脚本的执行顺序。尝试过异步、延迟、动态加载脚本,结果都出乎意料
- pandas - GeoViews 保存的内联 HTML 文件非常大
- c# - 警报框 MVC c#
- powershell - 如何更改 Visual Studio 代码“Powershell 集成控制台”?
- typescript - 使实现的接口中的可选道具不是可选的
- sql - 云存储的ms access数据库的pypyodbc sql查询在查询最新数据时速度很慢,但在查询最旧数据时速度很快
- azure - Azure 流分析:参考数据中的正则表达式
- python - AWS lambda:在本地调用可访问 s3 的 python lambda 函数
- c# - 您是否需要将曼哈顿距离用于 A* 寻路算法?
- python - 我想在 django 模板中使用 python 代码