TypeScript:使用具有未知名称的字段声明类型或接口



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

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

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

我试过了:

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

但是TypeScript理解Team中的所有字段都应该具有这种结构。

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

感谢

让我首先说我讨厌这种结构。如果有一种方法可以将代码重写为更符合逻辑的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<"myKey", string>解析为{ myKey: string; }

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

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

因此,我们团队的最终类型是:

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

这是意料之中的事。因为我们已经考虑到uid未定义的可能性,所以在不排除undefined的情况下,您无法通过与?if语句等的可选链接来访问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;
}
}

最新更新