Typescript: фильтр по параметру keyof type - PullRequest
2 голосов
/ 29 апреля 2020

Я использую машинопись 3.8.3 и пытаюсь динамически найти ключи определенного типа и использовать их для создания другого объекта.

У меня есть объект Detail, и я хочу использовать его для динамически генерировать объект Column только на основе свойств типа Desc. Вот упрощенный код того, что я хочу сделать:

// Model
interface Desc {
    creationDate: Date;
}

interface Address extends Desc {
    zipCode: number;
    adressName: string;
}

interface Order extends Desc {
    id: number;
    orderName: string;
}

interface Detail {
    name: string;
    address: Address[];
    orders: Order[];
}
// Table column configuration
interface Column<T> {
    field: keyof T;
    active: boolean;
}

type ColumnConfig<T> = { [P in keyof T]: Column<T[P] extends Desc ? P : never>[] };

const config: ColumnConfig<Detail> = {
    address: [
        {
            field: "zipCode",
            active: true 
        }, 
        {
            field: "addressName",
            active: true
        }
    ],
    order: [
        {
            field: "id",
            active:false
        },
        {
            field: "orderName",
            active: false
        }
    ],
    // Detail.name should not be available but it is

}

Как я могу воспользоваться помощью компилятора для создания моего config объекта и, таким образом, иметь возможность обнаруживать любые ошибки, если мой Detail объект меняется?

Спасибо!

1 Ответ

1 голос
/ 29 апреля 2020

Чтобы исключить некоторые столбцы для сопоставленного типа, нам нужно использовать промежуточный вспомогательный тип, позволяющий нам выбирать только ключи , соответствующие нашему условию, T[K] extends Desc:

type ConfigurableColumnsKeys<T extends object> = {
  [K in keyof T]: T[K] extends Desc ? K : never
}[keyof T];

Учитывая это, ColumnConfig просто нужно отобразить этот общий тип c вместо исходного keyof T:

type ColumnConfig<T extends object> = {
  [P in ConfigurableColumnsKeys<T>]: Column<P>[] 
};

Тогда ваш объект конфигурации будет правильно проверен:

  // Error
  name: [
    { field: 'abc', active: true }
  ]

Если вам нужно разрешить также массивы (т. Е. Address[] вместо Address), вы можете изменить тип помощника, отметив T extends Desc[]. Кроме того, вам понадобится также помощник UnboxArray, чтобы извлечь значение элемента Order[] -> Order для вашей конфигурации столбца:

type ConfigurableColumnsKeys<T extends object> = {
  [K in keyof T]: T[K] extends Desc ? K : T[K] extends Desc[] ? K : never
}[keyof T];

type UnboxArray<T> = T extends Array<infer V> ? V : T;

type ColumnConfig<T extends object> = {
  [P in ConfigurableColumnsKeys<T>]: Column<UnboxArray<T[P]>>[]
};

Вы можете увидеть его на работе на следующей площадке: Playground Link

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...