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

时间:2018-08-20 18:11:29

标签: typescript typescript2.0

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

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不是同态的。记录不是同态的一个线索是它不需要输入类型来复制以下属性:

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

就是这样。除以上引用外,在typescriptlang.org上没有其他提及Record

问题

  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}
    

2 个答案:

答案 0 :(得分:68)

  
      
  1. 有人可以简单地定义Record是什么吗?
  2.   

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

  
      
  1. Record<K,T>只是一种说法“此对象上的所有属性都将具有类型T”的一种方式吗?可能不是所有对象,因为K具有某些用途...
  2.   

您注意到,K的目的是……将属性键限制为特定值。如果要接受所有可能的字符串值键,则可以执行类似Record<string, T>的操作,但是惯用的方法是使用{ [k: string]: T }之类的index signature

  
      
  1. K泛型是否在对象上禁止使用非K的其他键,或者是否允许它们并且仅指示其属性未转换为T
  2.   

它并不完全“禁止”其他键:毕竟,通常允许一个值具有其类型中未明确提及的属性...但是它无法识别此类属性的存在:

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}
    
  2.   

是的!

希望有帮助。祝你好运!

答案 1 :(得分:9)

记录使您可以从联合创建新类型。 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]} />

如果以后扩展或更改状态联合,我知道我的状态组件将无法编译,并且会得到一个错误,可以立即修复。这使我可以向应用程序添加其他错误状态。

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