Типы Autopath/Path для lodash.get() с дополнительным ограничением

Мой вариант использования следующий: у меня есть таблица, в которой столбцы и их значения определяются объектом headers, например:

Для каждого filterable столбца я хочу сгенерировать список элементов из другого объекта (data) для подачи выборки.

Для простейшего случая, например столбца name, метод получения элементов может быть таким же простым, как следующий:

Эти типы помогают мне гарантировать, что метод получения всегда будет возвращать string | number для каждого фильтруемого столбца.

Проблемы начинают возникать, когда у меня есть более сложные ключи, такие как formulatorUser.code или особенно zdhc[0].subcategory, где геттер должен быть чем-то вроде этого:

На этом этапе мне по сути нужно создать типизации для lodash.get с дополнительным ограничением, чтобы быть фильтруемым столбцом. Я хотел позаимствовать Autopath/Path из ts-toolbelt, но они выглядят сломанными (и еще более сломанными в последних версиях Typescript, вплоть до того, что их невозможно использовать).

Не могли бы вы предложить рабочую реализацию Path/Autopath, которая работает с массивами и вложенными объектами и помогает реализовать дополнительное ограничение filterable?

const headers = [
  {
    key: 'data-table-select',
    unhidable: true
  },
  {
    title: t('name'),
    align: 'start',
    sortable: true,
    filterable: true,
    key: 'name'
  },
  {
    title: t('formulator-code'),
    align: 'start',
    sortable: true,
    filterable: true,
    key: 'formulatorUser.code',
    apiKey: 'code'
  },
  {
    title: t('zdhc_subcategory'),
    align: 'start',
    sortable: true,
    filterable: true,
    key: 'zdhc[0].subcategory',
    apiKey: 'subcategory'
  },
] as const satisfies DataTableHeader[]
interface MyData {
  id: string
  name: string
  formulatorUser: {
    id: string
    name: string
  }
  zdhc: Array<{
    id: string
    subcategory: string
  }>
}

const data: MyData[] = [...]
(header) => [...new Set(data.map(el => el[header.key as ApiKey<typeof headers>]))]

type ApiKey<T extends Array<{ key: string; filterable?: boolean }>> = {
  [K in keyof T]: T[K] extends { filterable: true }
    ? T[K] extends { key: string }
      ? T[K]['key']
      : never
    : never
}[number]
import { get } from 'lodash-es'

(header) => [...new Set(data.map(el => get(el, header.key)))]
Ананий
Вопрос задан21 января 2024 г.

1 Ответ

2
Мирослав
Ответ получен15 сентября 2024 г.

Ваш ответ

Загрузить файл.