如何在接口中 link keyof 类型

How to link keyof types within an interface

不确定这是否可行,但它与 keyof 有关,我很难理解...

我目前有这个界面:

interface Column<T> {
  header: string;
  field: keyof T;
  format?: (value: any) => string;
}

它的第一个用途是创建呈现 table 的东西,给定一个对象和列的列表。

const rows = [{name: 'Alice', age: 18}, {name: 'Bob', age: 12}];

type Row = typeof rows[0];

const columns: Column<Row>[] = [
  {
    header: 'Name',
    field: 'name',
    format: value => value.toUpperCase(),
  },
  {
    header: 'Age',
    field: 'age',
    format: value => value.toLocaleString(),
  },
];

const renderTable = <T>(rows: T[], columns: Columns<T>[]) { ... }
renderTable(rows, columns);

有没有办法去掉 format 函数中的 any 类型?以某种方式 "link" fieldkeyof Tformatvalue? IE。第一列 value 应该是 string,第二列应该是 number?


(我知道手动打印这些会很容易,但是也会向这个 table 添加一些自动魔法的东西,这将利用 fieldformat)

一种方法是依赖 TypeScript 的 mapped types.

这将 "map" 通过泛型传递 (Row) 中的每个键 (Key in keyof)。

然后对于每个 Row 键(例如:nameageadmin),我们将为其分配一个您使用属性勾勒出的形状的对象headerfieldformat

但是,由于我们现在知道我们正在使用特定的键(例如:age),我们可以使用 Key 来引用此映射类型中的 ageRow[Key] 引用 age 的类型 (number).

最后,您不需要带有嵌套对象的键,您只需要对象,这样我们就可以有效地 "pluck" 使用 [keyof Row] 的那些值,查找 [=27= 的所有值] 剩下的是所有可能的列的联合类型,正确键入 fieldformat

type Columns<Row> = {
  [Key in keyof Row]: {
    header: string;
    field: Key,
    format?: (value: Row[Key]) => string;
  }
}[keyof Row]

const rows = [{name: 'Alice', age: 18, admin: true }, {name: 'Bob', age: 12, admin: false}];

type Row = typeof rows[0];

const columns: Columns<Row>[] = [
  {
    header: 'Name',
    field: 'name',
    format: value => value.toUpperCase(), // value: string
  },
  {
    header: 'Age',
    field: 'age',
    format: value => value.toLocaleString(), // value: number
  },
 {
    header: 'Admin',
    field: 'admin',
    format: value => value.toString(), // value: boolean
  },
];

TypeScript Playground