ChatGPT解决这个技术问题 Extra ChatGPT

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

Record<K, T> 在 Typescript 中是什么意思?

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

// 对于 T 类型的每个属性 K,将其转换为 U function mapObject(obj: Record, f: (x: T) => U): Record

Typescript 2.1

Advanced Types 页面在 ReadonlyPartialPick 旁边的映射类型标题下提到了 Record,其定义似乎如下:

type Record = { [P in K]: T; }

Readonly、Partial 和 Pick 是同态的,而 Record 不是。 Record 不是同态的一个线索是它不需要输入类型来复制属性: type ThreeStringProps = Record<'prop1' | '道具2' | 'prop3',字符串>

就是这样。除了上述引文外,typescriptlang.org 上没有其他提及 Record

问题

有人可以简单定义一下 Record 是什么吗? Record 仅仅是一种说法“这个对象上的所有属性都将具有 T 类型”吗?可能不是所有的属性,因为 K 有一些目的...... K 泛型是否禁止对象上不是 K 的附加键,或者它是否允许它们并且只是表明它们的属性没有转换为 T?对于给定的示例: type ThreeStringProps = Record<'prop1' | '道具2' | 'prop3', string> 是不是和这个一模一样?:type ThreeStringProps = {prop1: string, prop2: string, prop3: string}

4. 的答案几乎是“是”,所以这可能应该回答你的其他问题。
在撰写有关 Record 的文档页面时,已弃用,在新页面中甚至没有提及这些类型
@CarmineTambascia 你有链接吗?旧的文档站点已被弃用,但我没有看到任何关于 Record 被弃用的信息。
@Matthias 我的意思和你一样,并不是说 Record 已被弃用。不再提及,只要我能看到。

j
jcalz

有人可以简单定义一下 Record 是什么吗?

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

Record 仅仅是一种说法“这个对象上的所有属性都将具有 T 类型”吗?可能不是所有的对象,因为 K 有一些目的......

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

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

对于给定的示例: type ThreeStringProps = Record<'prop1' | '道具2' | 'prop3', string> 是不是和这个一模一样?:type ThreeStringProps = {prop1: string, prop2: string, prop3: string}

是的!

希望有帮助。祝你好运!


学到了很多,还有一个问题,为什么“这样做的惯用方法是使用索引签名”而不是记录?我没有找到有关这种“惯用方式”的任何相关信息。
如果需要,您可以使用 Record<string, V> 来表示 {[x: string]: V};我什至可能自己也做过。索引签名版本更直接:它们是相同的类型,但前者是映射类型的类型别名,其计算结果为索引签名,而后者只是直接索引签名。在其他条件相同的情况下,我推荐后者。同样,除非有其他令人信服的上下文原因,否则我不会使用 Record<"a", string> 代替 {a: string}
“在其他条件相同的情况下,我推荐后者。”这是为什么?我的预 Typescript 自己同意,但我知道前者会更多,嗯,对于来自 C# 方面的人来说,自我评论,例如,对于 JavaScript 到 Typescripters 来说也不会更糟。您是否只是对跳过这些构造的转译步骤感兴趣?
只是我的看法:Record<string, V> 的行为只有在您已经知道索引签名在 TypeScript 中是如何工作的情况下才有意义。例如,给定 x: Record<string, string>x.foo 在编译时显然是 string,但实际上很可能是 string | undefined。这是 --strictNullChecks 工作方式的一个差距(参见 #13778)。我宁愿让新手直接处理 {[x: string]: V},而不是期望他们遵循从 Record<string, V>{[P in string]: V} 的链到索引签名行为。
Record 可以用作 C# 字典吗? Records 有 add()、remove() 方法吗?
P
Penny Liu

Record 允许您从联合创建新类型。 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"
  };

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

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

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

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


我假设大部分时间 type Statuses 生活在您未定义的类型中?否则我可以看到像一个更适合枚举的接口之类的东西,对吧?
嗨@victorio,我不确定枚举如何解决问题,如果你错过了一个键,你不会在枚举中得到错误。它只是键和值之间的映射。
我明白你现在的意思了。来自 C#,我们没有聪明的方法来做到这一点。最接近的是 Dictionary<enum, additional_metadata> 的字典。 Record 类型是表示枚举 + 元数据模式的好方法。
有没有办法初始化一个有多个键映射到单个值的记录?假设我有 10 种不同的状态,但在 UI 中,所有这些状态都应该显示一个警告图标。如果我使用记录类型,我将不得不复制相同的 10 次,如果我使用类似 switch 语句的东西,我将能够避免这种情况。
好吧,但是 const bla: CatNames = "miffy"; 有效。 TS 将 | 描述为联合类型,因此只需要 一个,但记录需要全部。非常混乱。 JS 和 TS 还是一团糟。