【问题标题】:TypeScript: declare a type or an interface with a field that has an unknow nameTypeScript:使用未知名称的字段声明类型或接口
【发布时间】:2021-01-13 13:33:12
【问题描述】:

我必须为团队对象声明一个接口:

export interface Team{
  memberUid?: {
    mail: string
    name: string
    photoURL: string
  }
  startDate: Timestamp
  endDate: Timestamp
  agenda: Array<{
    date: Date | Timestamp
    title: string
    description: string
  }>
}

会有几个成员 Uid。我不知道如何在 TypeScript 中声明它。

我试过了:

[memberUid: string] : {
  mail: string
  name: string
  photoURL: string
}

然后 TypeScript 明白 Team 中的所有字段都应该具有这种结构。

处理这个问题的正确方法是什么?

谢谢

【问题讨论】:

标签: typescript typescript-typings typescript-types


【解决方案1】:

首先让我说我讨厌这种结构。如果有办法将代码重写为更合乎逻辑的Team 类型,那就去做吧。但是能做到吗?是的,它可以。 Team 必须是 type 而不是接口,因为接口只能有已知的键。

让我们先把它分成几块。

TeamBase 定义了始终存在的属性:

interface TeamBase {
  startDate: Timestamp
  endDate: Timestamp
  agenda: Array<{
    date: Date | Timestamp
    title: string
    description: string
  }>
}

UidProperties 定义了未知键的内容:

interface UidProperties {
    mail: string
    name: string
    photoURL: string
}

这是一个实用类型,可用于使用映射类型根据键的类型声明属性:

type HasProperty<Key extends keyof any, Value> = {
    [K in Key]: Value;
}

如果通用 Key 是字符串文字,那么 K in Key 的唯一可能值就是那个确切的字符串,所以 HasProperty&lt;"myKey", string&gt; 解析为 { myKey: string; }

所以现在我们需要定义类型Team。我们知道它需要包含TeamBase 的所有属性,并且我们知道有一些字符串键的值为UidProperties。之前给您带来问题的一个重要事实是此键不能是 TeamBase 的键之一。所以我们不使用string,而是使用Exclude&lt;string, keyof TeamBase&gt;

您可以使用HasProperty&lt;...&gt; 表示每个 不是TeamBase 键的字符串键的值为UidProperties,但我认为最好使用Partial&lt;HasProperty&lt;...&gt;&gt;,它说这些未知的字符串键中的任何一个都可以是UidProperties,但也可以是undefined。当您访问一个未知的密钥时,您可能需要再次检查该值。

所以我们最终的 Team 类型是:

export type Team = TeamBase & Partial<HasProperty<Exclude<string, keyof TeamBase>, UidProperties>>

这按预期工作。因为我们已经考虑到uid 未定义的可能性,所以如果不通过? 的可选链接或if 语句等排除undefined,就不能访问uid 的属性。

function f1(team: Team) {

    const startDate: Timestamp = team.startDate;

    const uid: UidProperties | undefined = team['randomKey']

    const name = uid?.name;

    if ( uid !== undefined ) {
        const mail = uid.mail;
    }
}

【讨论】:

    猜你喜欢
    • 2017-05-28
    • 2015-09-30
    • 2013-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-15
    • 2019-05-24
    相关资源
    最近更新 更多