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

Mat*_*ley 117 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>
Run Code Online (Sandbox Code Playgroud)

Typescript 2.1

先进的各类网页提到Record下的映射类型标题旁边Readonly,PartialPick,这似乎是它的定义:

type Record<K extends string, T> = {
    [P in K]: T;
}
Run Code Online (Sandbox Code Playgroud)

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

type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
Run Code Online (Sandbox Code Playgroud)

就是这样.除了上述报价,没有其他提Recordtypescriptlang.org.

问题

  1. 有人可以给出一个简单的定义Record吗?

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

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

  4. 以给定的例子:

    type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
    
    Run Code Online (Sandbox Code Playgroud)

    它跟这个完全一样吗?:

    type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
    
    Run Code Online (Sandbox Code Playgroud)

jca*_*alz 131

  1. 有人可以给出一个简单的定义Record吗?

A 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>,但这样做的惯用方法是使用一个索引的签名一样{ [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>'
Run Code Online (Sandbox Code Playgroud)

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

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

有时接受:

const y = {a: "hey", b: "you"};
acceptR(y); // okay
Run Code Online (Sandbox Code Playgroud)
  1. 以给定的例子:

    type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
    
    Run Code Online (Sandbox Code Playgroud)

    它跟这个完全一样吗?:

    type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
    
    Run Code Online (Sandbox Code Playgroud)

是!

希望有所帮助.祝好运!

  • 如果需要,您可以使用“Record&lt;string, V&gt;”来表示“{[x: string]: V}”;我什至可能自己也做过这样的事。索引签名版本更直接:它们是相同的类型,但前者是映射类型的类型别名,其计算结果为索引签名,而后者只是直接的索引签名。在其他条件相同的情况下,我推荐后者。同样,我不会使用 `Record&lt;"a", string&gt;` 来代替 `{a: string}` ,除非有其他令人信服的上下文原因这样做。 (10认同)
  • 学到了很多东西,还有一个问题,为什么“这样做的惯用方法是使用索引签名”而不是记录签名?我没有找到任何关于这种“惯用方式”的相关信息。 (5认同)
  • 只是我的观点:只有当您已经知道索引签名在 TypeScript 中如何工作时,“Record&lt;string, V&gt;”的行为才有意义。例如,给定 `x: Record&lt;string, string&gt;`,`x.foo` 在编译时显然是一个 `string`,但实际上很可能是 `string | 未定义`。这是 `--strictNullChecks` 工作方式中的一个差距(请参阅 [#13778](https://github.com/microsoft/TypeScript/issues/13778))。我宁愿让新手直接处理 `{[x: string]: V}` 而不是期望他们遵循从 `Record&lt;string, V&gt;` 到 `{[P in string]: V}` 的链条索引签名行为。 (4认同)
  • “_在其他条件相同的情况下,我推荐后者。_”为什么呢?我的 Typescript 之前的自我同意,但我知道前者对于来自 C# 方面的人来说会更多,嗯,自我评论,例如,对于 JavaScript 到 Typescripters 来说也不会更糟。您是否只是想跳过这些结构的转译步骤? (3认同)
  • @KishanVaishnav 不,它只是一个带有键和值的普通对象类型。听起来你宁愿使用类似 [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) 的东西。 (2认同)

sup*_*ary 32

记录使您可以从联合创建新类型。联合中的值用作新类型的属性。

例如,说我有一个这样的联合会:

type CatNames = "miffy" | "boris" | "mordred";
Run Code Online (Sandbox Code Playgroud)

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

type CatList = Record<CatNames, {age: number}>
Run Code Online (Sandbox Code Playgroud)

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

const cats:CatList = {
  miffy: { age:99 },
  boris: { age:16 },
  mordred: { age:600 }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 如果我忘记了猫,就会报错。
  • 如果我添加了不允许的猫,则会出现错误。
  • 如果以后更改CatNames,则会收到错误消息。这特别有用,因为CatNames可能是从另一个文件导入的,并且可能在许多地方使用。

实际的React示例。

我最近用它来创建一个Status组件。该组件将收到状态道具,然后呈现一个图标。为了说明起见,我在这里简化了很多代码

我有一个这样的工会:

type Statuses = "failed" | "complete";
Run Code Online (Sandbox Code Playgroud)

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

const icons: Record<
  Statuses,
  { iconType: IconTypes; iconColor: IconColors }
> = {
  failed: {
    iconType: "warning",
    iconColor: "red"
  },
  complete: {
    iconType: "check",
    iconColor: "green"
  };
Run Code Online (Sandbox Code Playgroud)

然后可以通过将对象中的元素分解为prop来进行渲染,如下所示:

const Status = ({status}) => <Icon {...icons[status]} />
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我明白你的意思了。来自 C# 我们没有聪明的方法来做到这一点。最接近的就是“Dictionary&lt;enum, additional_metadata&gt;”的字典。Record 类型是表示枚举 + 元数据模式的好方法。 (2认同)

Fli*_*lip 9

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

引用一下:

记录<键,类型> 发布:2.1

构造一个对象类型,其属性键为 Keys,属性值为 Type。该实用程序可用于将一种类型的属性映射到另一种类型。

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>
Run Code Online (Sandbox Code Playgroud)