typescript 打字稿中的记录类型是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/51936369/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 07:57:23  来源:igfitidea点击:

What is the Record type in typescript?

typescripttypescript2.0

提问by Matthias

What is does Record<K, T>mean in Typescript?

Record<K, T>打字稿中的意思是什么?

Typescript 2.1 introduced the Recordtype, describing it in an example:

Typescript 2.1 引入了Record类型,在示例中对其进行了描述:

// For every properties K of type T, transform it to U
function mapObject<K extends string, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>
// For every properties K of type T, transform it to U
function mapObject<K extends string, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>

see Typescript 2.1

打字稿 2.1

And the Advanced Typespage mentions Recordunder the Mapped Types heading alongside Readonly, Partial, and Pick, in what appears to be its definition:

高级类型页提到Record的映射类型旁边标题下ReadonlyPartialPick,这似乎是它的定义:

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

Readonly, Partial and Pick are homomorphic whereas Record is not. One clue that Record is not homomorphic is that it doesn't take an input type to copy properties from:

type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
type Record<K extends string, T> = {
    [P in K]: T;
}

Readonly、Partial 和 Pick 是同态的,而 Record 不是。Record 不是同态的一个线索是它不需要输入类型来复制属性:

type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>

And that's it. Besides the above quotes, there is no other mention of Recordon typescriptlang.org.

就是这样。除了上面的引用之外,Recordtypescriptlang.org上没有其他提及。

Questions

问题

  1. Can someone give a simple definition of what Recordis?

  2. Is Record<K,T>merely a way of saying "all properties on this object will have type T"? Probably not allproperties, since Khas some purpose...

  3. Does the Kgeneric 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?

  4. 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}
    
  1. 有人可以给出一个简单的定义是什么Record吗?

  2. Record<K,T>仅仅说“此对象上的所有属性都会有型的方式T”?可能不是所有的属性,因为K有一些目的......

  3. K泛型是否禁止对象上的附加键K,或者它是否允许它们并且只是指示它们的属性没有转换为T

  4. 使用给定的示例:

    type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
    

    和这个完全一样吗?:

    type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
    

回答by jcalz

  1. Can someone give a simple definition of what Recordis?
  1. 有人可以给出一个简单的定义是什么Record吗?

A Record<K, T>is an object type whose property keys are Kand whose property values are T. That is, keyof Record<K, T>is equivalent to K, and Record<K, T>[K]is (basically) equivalent to T.

ARecord<K, T>是一个对象类型,其属性键为K,属性值为T。也就是说,keyof Record<K, T>相当于K,并且Record<K, T>[K](基本上)相当于T

  1. Is Record<K,T>merely a way of saying "all properties on this object will have type T"? Probably not all objects, since Khas some purpose...
  1. Record<K,T>仅仅说“此对象上的所有属性都会有型的方式T”?可能不是所有的对象,因为K有一些目的......

As you note, Khas a purpose... to limit the property keys to particular values. If you want to accept all possible string-valued keys, you could do something like Record<string, T>, but the idiomatic way of doing that is to use an index signaturelike { [k: string]: T }.

正如您所注意到的,K有一个目的......将属性键限制为特定值。如果要接受所有可能的字符串值的键,你可以不喜欢Record<string, T>,但这样做的惯用方法是使用一个索引的签名一样{ [k: string]: T }

  1. Does the Kgeneric 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?
  1. K泛型是否禁止对象上的附加键K,或者它是否允许它们并且只是指示它们的属性没有转换为T

It doesn't exactly "forbid" additional keys: after all, a value is generally allowed to have properties not explicitly mentioned in its type... but it wouldn't recognize that such properties exist:

它并没有完全“禁止”额外的键:毕竟,通常允许一个值具有在其类型中没有明确提及的属性......但它不会识别出这样的属性存在:

declare const x: Record<"a", string>;
x.b; // error, Property 'b' does not exist on type 'Record<"a", string>'

and it would treat them as excess propertieswhich are sometimes rejected:

它会将它们视为有时会被拒绝的多余属性

declare function acceptR(x: Record<"a", string>): void;
acceptR({a: "hey", b: "you"}); // error, Object literal may only specify known properties

and sometimes accepted:

有时接受:

const y = {a: "hey", b: "you"};
acceptR(y); // okay
  1. 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}
    
  1. 使用给定的示例:

    type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
    

    和这个完全一样吗?:

    type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
    

Yes!

是的!

Hope that helps. Good luck!

希望有帮助。祝你好运!

回答by superluminary

A Record lets you create a new type from a Union. The values in the Union are used as attributes of the new type.

记录允许您从联合创建新类型。联合中的值用作新类型的属性。

For example, say I have a Union like this:

例如,假设我有一个这样的联盟:

type CatNames = "miffy" | "boris" | "mordred";

Now I want to create an object that contains information about all the cats, I can create a new type using the values in the CatName Union as keys.

现在我想创建一个包含所有猫信息的对象,我可以使用 CatName Union 中的值作为键创建一个新类型。

type CatList = Record<CatNames, {age: number}>

If I want to satisfy this CatList, I must create an object like this:

如果我想满足这个 CatList,我必须创建一个这样的对象:

const cats:CatList = {
  miffy: { age:99 },
  boris: { age:16 },
  mordred: { age:600 }
}

You get very strong type safety:

您将获得非常强大的类型安全性:

  • If I forget a cat, I get an error.
  • If I add a cat that's not allowed, I get an error.
  • If I later change CatNames, I get an error. This is especially useful because CatNames is likely imported from another file, and likely used in many places.
  • 如果我忘记了一只猫,我会得到一个错误。
  • 如果我添加了不允许的猫,则会出现错误。
  • 如果我稍后更改 CatNames,则会出现错误。这特别有用,因为 CatNames 可能是从另一个文件导入的,并且可能在许多地方使用。

Real-world React example.

真实世界的 React 示例。

I used this recently to create a Status component. The component would receive a status prop, and then render an icon. I've simplified the code quite a lot here for illustrative purposes

我最近用它来创建一个状态组件。该组件将接收一个状态道具,然后呈现一个图标。出于说明目的,我在这里大大简化了代码

I had a union like this:

我有一个这样的工会:

type Statuses = "failed" | "complete";

I used this to create an object like this:

我用它来创建一个这样的对象:

const icons: Record<
  Statuses,
  { iconType: IconTypes; iconColor: IconColors }
> = {
  failed: {
    iconType: "warning",
    iconColor: "red"
  },
  complete: {
    iconType: "check",
    iconColor: "green"
  };

I could then render by destructuring an element from the object into props, like so:

然后我可以通过将对象中的元素解构为 props 来渲染,如下所示:

const Status = ({status}) => <Icon {...icons[status]} />

If the Statuses union is later extended or changed, I know my Status component will fail to compile and I'll get an error that I can fix immediately. This allows me to add additional error states to the app.

如果稍后扩展或更改 Statuses 联合,我知道我的 Status 组件将无法编译并且我会收到一个我可以立即修复的错误。这允许我向应用程序添加额外的错误状态。

Note that the actual app had dozens of error states that were referenced in multiple places, so this type safety was extremely useful.

请注意,实际的应用程序有许多错误状态在多个地方被引用,因此这种类型安全非常有用。