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

问题描述 投票:62回答:2

Record<K, T>在Typescript中的含义是什么?

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>

Typescript 2.1

Advanced Types页面在RecordReadonlyPartial的映射类型标题下提到Pick,似乎是它的定义:

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

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

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

就是这样。除了上面的引用,还没有提到Record上的typescriptlang.org

问题

  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}
typescript typescript2.0
2个回答
109
投票
  1. 有人可以给出Record的简单定义吗?

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

  1. Record<K,T>只是说“这个物体上的所有属性都有T类型”吗?可能不是所有的对象,因为K有一些目的......

如你所知,K有一个目的......将属性键限制为特定值。如果你想接受所有可能的字符串值键,你可以做类似Record<string, T>的事情,但这样做的惯用方法是使用像index signature这样的{ [k: string]: T }

  1. K是否禁止对象上的其他键不是K,还是允许它们只是表明它们的属性没有转换为T

它并不完全“禁止”其他密钥:毕竟,一般来说,一个值通常允许在其类型中没有明确提到的属性......但是它不会识别出存在这样的属性:

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

并将它们视为excess properties,有时被拒绝:

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
  1. 以给定的例子: type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string> 它跟这个完全一样吗?: type ThreeStringProps = {prop1: string, prop2: string, prop3: string}

是!

希望有所帮助。祝好运!


20
投票

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

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

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

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

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"
  };

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

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

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

请注意,实际应用程序有多个错误状态,这些错误状态在多个位置引用,因此这种类型的安全性非常有用。

© www.soinside.com 2019 - 2024. All rights reserved.