Как связать ключевые типы в интерфейсе - PullRequest
0 голосов
/ 19 сентября 2019

Не уверен, что это возможно, но это связано с keyof, который я с трудом собираю ...

У меня в настоящее время есть этот интерфейс:

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

Первое использование для этого - создать что-то, что визуализирует таблицу, учитывая список объектов и столбцов.

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);

Есть ли способ избавиться от типа any здесь, в format функция?Как-то «связать» keyof T из field с value из format?Т.е. для первого столбца value должно быть string, а для второго - number?


(я знаю, что было бы очень просто распечатать их вручную, нок этой таблице также будут добавлены некоторые магические материалы, которые будут использовать field и format)

1 Ответ

2 голосов
/ 19 сентября 2019

Один из подходов состоит в том, чтобы полагаться на сопоставленные типы TypeScript .

. Это будет "отображать" все ключи (Key in keyof) в переданном родовом (Row).

Затем для каждой клавиши Row (например, name, age, admin) мы назначим объект формы, который вы обрисовали, со свойствами header, field и format.

Однако, поскольку теперь мы знаем, что работаем с конкретным ключом (например, age), мы можем использовать Key для ссылки на age в этом отображенном наборе и Row[Key] для ссылки на типиз age (number).

Наконец, вам не нужны ключи с вложенными объектами, вам нужны только объекты, поэтому мы можем эффективно «собрать» эти значения с помощью [keyof Row], просматривая всезначения для "age" | "name" | "admin" и оставленный тип объединения всех возможных столбцов с правильно набранными field и format.

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

...