记录类型是什么?

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>

看到打字稿2.1

先进的类型页面在映射类型标题下提到了Record,旁边是ReadonlyPartialPick,这似乎是它的定义:

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

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

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

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

问题

  1. 有人能给Record一个简单的定义吗?

  2. Record<K,T>仅仅是表示“此对象上的所有属性都将具有__abc1类型”的一种方式吗?可能不是所有属性,因为K有一些用途…

  3. K泛型是否禁止对象上非K的附加键,还是允许它们,只是表明它们的属性没有转换为T?

  4. 与给定的例子:

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

    和这个完全一样吗?:

    type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
    
360965 次浏览
  1. 谁能简单定义一下Record是什么?

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

  1. Record<K,T>仅仅是表示“此对象上的所有属性都将具有__abc1类型”的一种方式吗?可能不是所有的对象,因为K有一些用途…

正如你所注意到的,K有一个目的…将属性键限制为特定值。如果你想接受所有可能的字符串值的键,你可以做一些类似Record<string, T>的事情,但惯用的方法是使用{ [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>'

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

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}

是的!

希望这能有所帮助。好运!

Record可以让你从联合中创建一个新类型。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组件。该组件将接收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]} />

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

注意,实际的应用程序有几十个错误状态,在多个地方被引用,所以这种类型安全是非常有用的。

使用Record的简单例子:

假设我们有以下对象,我们想为它定义一个对象类型。

const networkConfig = {
4: {
name: "rinkeby",
ethUsdPriceFeed: "0x8A753747A1Fa494EC906cE90E9f37563A8AF630e",
}
}

因此,该类型将像下面使用Record:

type networkConfigType = Record<number, {
name: string;
ethUsdPriceFeed: string;
}>;

现在有一个稍微长一点的记录类型文档: https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type < / p >

引用:

< p > Record<键,Type> 发布: 2.1 < / p >

构造一个对象类型,其属性键为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>