Record<K, T>在Typescript中是什么意思?
Typescript 2.1引入了Record类型,在一个例子中描述了它:
//对于每一个T类型的属性K,将其转换为U
函数mapObject<K扩展字符串,T, U>(obj:记录<K, T>, f: (x: T) => U):记录<K, U>
参见Typescript 2.1
高级类型页面在映射类型标题下提到了Record,与Readonly, Partial和Pick并列,这似乎是它的定义:
type记录<K扩展字符串,T> = {
[P in K]: T;
}
Readonly、Partial和Pick是同态的,而Record不是。Record不是同态的一个线索是,它不需要输入类型来复制属性:
type ThreeStringProps =记录<'prop1' | 'prop2' | 'prop3',字符串>
就是这样。除了上面的引用,typescriptlang.org上没有提到Record。
问题
Can someone give a simple definition of what Record is?
Is Record<K,T> merely a way of saying "all properties on this object will have type T"? Probably not all properties, since K has some purpose...
Does the K generic forbid additional keys on the object that are not K, or does it allow them and just indicate that their properties are not transformed to T?
With the given example:
type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
Is it exactly the same as this?:
type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
有人能给什么是唱片下个简单的定义吗?
A Record<K, T>是属性键为K,属性值为T的对象类型,即keyof Record<K, T>等价于K, Record<K, T>[K](基本)等价于T。
Record<K,T>仅仅是表示“这个对象上的所有属性都有类型T”的一种方式吗?可能不是所有的对象,因为K有某种目的……
正如你所注意到的,K是有目的的……将属性键限制为特定值。如果您想接受所有可能的字符串值键,您可以执行类似Record<string, T>这样的操作,但惯用的方法是使用类似{[k: string]: T}的索引签名。
泛型K是禁止对象上非K的附加键,还是允许它们,只是指出它们的属性没有转换为T?
它并没有完全“禁止”附加键:毕竟,值通常允许具有没有在其类型中显式提及的属性……但它不会认识到这样的属性存在:
declare const x: Record<"a", string>;
x.b; // error, Property 'b' does not exist on type 'Record<"a", string>'
它会把它们视为多余的财产,有时会被拒绝:
declare function acceptR(x: Record<"a", string>): void;
acceptR({a: "hey", b: "you"}); // error, Object literal may only specify known properties
有时被接受:
const y = {a: "hey", b: "you"};
acceptR(y); // okay
用下面的例子:
type ThreeStringProps =记录<'prop1' | 'prop2' | 'prop3',字符串>
和这个完全一样吗?:
类型ThreeStringProps = {prop1:字符串,prop2:字符串,prop3:字符串}
Yes!
现在有一个稍微长一点的Record类型文档:
https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type
引用:
记录<键类型>
发布:
2.1
构造一个对象类型,其属性键为keys,其属性为
值为“类型”。此实用程序可用于映射类型的属性
另一种类型。
interface CatInfo {
age: number;
breed: string;
}
type CatName = "miffy" | "boris" | "mordred";
const cats: Record<CatName, CatInfo> = {
miffy: { age: 10, breed: "Persian" },
boris: { age: 5, breed: "Maine Coon" },
mordred: { age: 16, breed: "British Shorthair" },
};
cats.boris;
const cats: Record<CatName, CatInfo>
Record允许您从Union创建一个新类型。Union中的值被用作新类型的属性。
例如,假设我有一个这样的Union:
type CatNames = "miffy" | "boris" | "mordred";
现在我想创建一个包含所有猫信息的对象,我可以使用CatNames联合中的值作为键来创建一个新类型。
type CatList = Record<CatNames, {age: number}>
如果我想满足这个CatList,我必须创建一个这样的对象:
const cats: CatList = {
miffy: { age:99 },
boris: { age:16 },
mordred: { age:600 }
}
你会得到非常强的类型安全性:
如果我忘记了一只猫,就会得到一个错误。
如果我添加了不允许的猫,就会得到一个错误。
如果稍后更改CatNames,则会得到一个错误。这一点特别有用,因为CatNames可能是从另一个文件导入的,并且可能在许多地方使用。
真实世界的React示例。
我最近用它创建了一个Status组件。组件将接收一个状态道具,然后呈现一个图标。为了便于说明,我在这里对代码进行了大量简化
我的工会是这样的:
type Statuses = "failed" | "complete";
我用它创建了一个这样的对象:
const icons: Record<
Statuses,
{ iconType: IconTypes; iconColor: IconColors }
> = {
failed: {
iconType: "warning",
iconColor: "red"
},
complete: {
iconType: "check",
iconColor: "green"
};
然后我可以通过将对象中的元素解构为props来渲染,如下所示:
const Status = ({status}) => <Icon {...icons[status]} />
如果后来扩展或更改了Status联合,我知道我的Status组件将无法编译,并将得到一个可以立即修复的错误。这允许我向应用程序添加额外的错误状态。
注意,实际的应用程序有几十个错误状态,在多个地方被引用,所以这种类型安全是非常有用的。