Как использовать array как const для указания возможных индексов в TypeScript подписи индекса?

#typescript #types

#typescript #типы

Вопрос:

Я хочу создать массив, в котором будет указано, какие строки будут индексировать свойства внутри объекта и что свойства объекта содержат только функции.

Что я понимаю, так это то, что я могу создать тип объединения только из массива:

Мой рабочий случай — это действие редуктора (инструкция) в React reducer (но его можно использовать в другом месте):

 const InstructionsArray = [
    'HANDLE_BUTTON_CONVERT_INPUT',
    'HANDLE_CHECKBOX_CONVERT_ON_INPUT',
    'HANDLE_CHECKBOX_DISPLAY_TAGS',
    'HANDLE_TEXTAREA_INPUT',
    'HANDLE_RUNTIME'
] as const;
  

Затем у меня есть объект типа со свойством:

 instruction: typeof InstructionsArray[number]
  

Конечно, обычный массив позволил бы нам использовать любую строку в качестве индексов, но поскольку мы привели его как const , теперь он допускает только строки, которые мы указали в array .

Что я на самом деле хочу, так это иметь объект, который будет иметь некоторые имена свойств as string , и все свойства будут иметь значение function . Я хотел бы указать только эти имена свойств ( string ) , но поскольку каждое значение будет a function , я бы не хотел указывать его более одного раза, чтобы его можно было принять как должное.

Текущий код выглядит так:

 const changersLabels = [
    'inventory',
    'quest'
] as const;
  

Но «тот же» способ не работает с подобным объектом:

 keyboardRouter(changers: {[key:typeof changersLabels[number]:Function]}) {

    //some stuff

}
  

Что я делаю не так и возможно ли это вообще?

Ответ №1:

Похоже, вам просто нужен сопоставленный тип, в котором есть ключи typeof changersLabels[number] и все свойства Function :

 function keyboardRouter(changers: { [K in typeof changersLabels[number]]: Function }) {
  changers.inventory // Function
  changers.quest // Function
}
  

Сопоставленный тип немного похож на тип с подписью индекса, но это работает только там, где индекс имеет тип string или тип number . Для других типов, таких как объединение строковых литералов, вам нужен сопоставленный тип с in оператором.

Который можно было бы слегка переработать, чтобы присвоить имя вашим ключам и использовать встроенный Record тип утилиты:

 type ChangersLabels = typeof changersLabels[number];
function keyboardRouter2(changers: Record<ChangersLabels, Function>) {
  changers.inventory // Function
  changers.quest // Function
}
  

Игровая площадка ссылка на код