如何在 Typescript 中定义接受零个或多个动态命名属性的接口

How to define an interface that accepts zero or more dynamically named attributes in Typescript

我的界面如下所示:

export interface ReportingNodeConfig {
  template: string;
  dashboardName: string;
  dashboardDescription: string;
  reportUrlSelect: SelectProps.Option;
  platformSelect: SelectProps.Option;
}

执行我上面定义的接口同时允许与特定类型匹配的其他动态属性的正确模式是什么?

换句话说,我如何定义一个接口来要求其中的所有属性都存在,但也允许零个或多个特定类型的附加属性但动态键名。

其他值可能遵循 [key: string]: string

模式

一个实际的对象看起来像这样:

{
  template: "test",
  dashboardName: "foo",
  dashboardDescription: "bar"
  reportUrlSelect: "test1"
  platformSelect: "hello world",
  dynamicallyGeneratedAttr: "I might not always be here",
  anotherDynamicAttr: "I'm also not guaranteed to be here all the time"
}

我知道我可以扩展接口并且还阅读了关于接口的 dynamic keys 但动态密钥在这种情况下不起作用。

谢谢。

记录

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

TS Docs 中有更好的解释。

解决方案

您可能想要使用 Record<string, string>

您可以合并索引签名:

type Foo = ReportingNodeConfig & { [key: string]: string | undefined }

正在测试:

declare const foo: Foo

foo.template // string
foo.reportUrlSelect // SelectProps.Option

if (foo.someUnknownPropHere) {
    foo.someUnknownPropHere // string here
}

不过,您肯定希望它解析为与 undefined 的联合,因为当您查找这些属性时,您无法确定它们是否确实存在。

Playground


就是说,如果您可以更改此数据模型,那么您可能应该这样做。如果您有自由格式的 属性 名称,那么它们很可能是完全不同类型的数据,应该存储在嵌套对象中。

喜欢说:

export interface ReportingNodeConfig {
  template: string;
  dashboardName: string;
  dashboardDescription: string;
  reportUrlSelect: SelectProps.Option;
  platformSelect: SelectProps.Option;
  customData: Record<string, string | undefined>
}

现在您可以在 customData 中塞入任何内容,而不会污染可静态验证的 属性 名称。