来自自己的动态界面 属性

Dynamic Interface from own property

我想知道这在 TypeScript 上是否可行。

我有这样的界面:

interface ComplexTable extends BaseTable {
    headers: HeaderOptions[];
    datas: { [id: string]: string }[];
  }

而 HeaderOptions 只是一个带有标签和 id 的接口

有没有办法只允许数据 headers 之前给出的 ID?

比如我有

const table: ComplexTable = {
  headers: [
    { id: 'a', label: 'Name' },
    { id: 'b', label: 'Last Name' },
  ]
}

我不想只允许在数据 objects 上只使用键 'a' 和 'b'。

这应该有效

const table: ComplexTable = {
  headers: [
    { id: 'a', label: 'Name' },
    { id: 'b', label: 'Last Name' },
  ],
  datas: someData.map((data) => ({
    a: data.someValue,
    b: data.someOtherValue
  }))
}

这应该行不通

const table: ComplexTable = {
  headers: [
    { id: 'a', label: 'Name' },
    { id: 'b', label: 'Last Name' },
  ],
  datas: someData.map((data) => ({
    a: data.someValue,
    c: data.someOtherValue
  }))
}

你可以做到这一点,但这需要一些工作:

  • 您需要参数化 ComplexTable,以便它可以将相同的规则应用于其成员 headersdatas
  • 您需要参数化 HeaderOptions 以便它可以从 id 中读取密钥,而不是将它们视为普通的 string
  • 您需要指定 datas 才能使用 mapped type [id in K]
  • 在构建 table.
  • 时,您需要一个恒等函数

看起来像这样:

interface HeaderOptions<K> {
  id: K;
  label: string;
}

interface ComplexTable<K extends string> extends BaseTable {
  headers: HeaderOptions<K>[];
  datas: { [id in K]: string }[];
}

function complexTable<K extends string>(table: ComplexTable<K>) {
  return table;
}

所以你可以像这样调用它:

const shouldWork = complexTable({
  headers: [
    { id: 'a', label: 'Name' },
    { id: 'b', label: 'Last Name' },
  ],
  datas: someData.map((data) => ({
    a: data.someValue,
    b: data.someOtherValue
  }))
});

Playground link

请注意,就像在 playground 中一样,TypeScript 不会介意您提供的数据键多于它在 headers 中预期的数据键;但是,如果缺少任何数据键,它会抱怨。