Параметр типа подписки индекса не может быть объединенным типом. Рассмотрите возможность использования типизированного объекта вместо этого!
Я пытаюсь использовать следующий паттерн:
enum Option {
ONE = 'one',
TWO = 'two',
THREE = 'three'
}
interface OptionRequirement {
someBool: boolean;
someString: string;
}
interface OptionRequirements {
[key: Option]: OptionRequirement;
}
На первый взгляд, всё выглядит довольно понятно, однако я получаю следующую ошибку:
An index signature parameter type cannot be a union type. Consider using a mapped object type instead.
Что я делаю не так?
5 ответ(ов)
Самое простое решение — использовать Record
:
type OptionRequirements = Record<Options, OptionRequirement>;
Вы также можете реализовать это самостоятельно следующим образом:
type OptionRequirements = {
[key in Options]: OptionRequirement;
}
Этот конструкция доступна только для type
, но не для interface
.
Проблема в вашем определении заключается в том, что вы указываете, что ключ вашего интерфейса должен быть типа Options
, в то время как Options
является перечислением, а не строкой, числом или символом.
key in Options
означает "для тех специфических ключей, которые находятся в объединенном типе Options".
Псевдоним type
более гибок и мощен по сравнению с interface
.
Если ваш тип не нужно использовать в классе, выбирайте type
вместо interface
.
В вашем случае проблема заключалась в использовании двоеточия :
в определении типа для ключей в объекте. Это вызывало ошибку. Чтобы исправить это, вы можете использовать оператор in
, который позволяет корректно задать типы для ключей.
Вот исправленный код:
export type PossibleKeysType =
| 'userAgreement'
| 'privacy'
| 'people';
interface ProviderProps {
children: React.ReactNode;
items: {
// ↙ используйте оператор "in"
[key in PossibleKeysType]: Array<SectionItemsType>;
};
}
Таким образом, если вы замените :
на in
, ваш интерфейс будет корректно определять ключи, и это решит возникшую проблему.
У меня была похожая проблема, но в моем случае это касалось другого свойства интерфейса. В качестве примера, вот мое решение с необязательным свойством поля и перечислением для ключей:
export enum ACTION_INSTANCE_KEY {
cat = 'cat',
dog = 'dog',
cow = 'cow',
book = 'book'
}
type ActionInstances = {
[key in ACTION_INSTANCE_KEY]?: number; // id кота/id собаки/id коровы и т.д. // <== необязательное
};
export interface EventAnalyticsAction extends ActionInstances { // <== нужно расширять
marker: EVENT_ANALYTIC_ACTION_TYPE; // <== если хотите добавить еще одно поле в интерфейс
}
Таким образом, вы можете добавить любые дополнительные поля в интерфейс EventAnalyticsAction
, сохраняя при этом возможность использования перечисления для ключей, что значительно упрощает работу с ними. Не забудьте, что свойства, указанные в ActionInstances
, являются необязательными, поэтому вы можете работать с частичными данными.
В вашем случае, если вам нужно, чтобы свойства были опциональными, вы можете создать следующий обобщенный тип:
type PartialRecord<K extends string | number | symbol, T> = { [P in K]?: T; };
После этого вы можете использовать его следующим образом:
type MyTypes = 'TYPE_A' | 'TYPE_B' | 'TYPE_C';
interface IContent {
name: string;
age: number;
}
interface IExample {
type: string;
partials: PartialRecord<MyTypes, IContent>;
}
Вот пример использования:
const example: IExample = {
type: 'some-type',
partials: {
TYPE_A: {
name: 'name',
age: 30
},
TYPE_C: {
name: 'another name',
age: 50
}
}
}
Такой подход позволяет вам гибко задавать опциональные свойства в объекте partials
, при этом обеспечивая хорошую типизацию и поддержку IntelliSense.
Вместо использования интерфейса, можно применить тип отображаемого объекта. Вот пример, как это можно сделать:
enum Option {
ONE = 'one',
TWO = 'two',
THREE = 'three'
}
type OptionKeys = keyof typeof Option;
interface OptionRequirement {
someBool: boolean;
someString: string;
}
type OptionRequirements = { // обратите внимание, это тип, а не интерфейс
[key in OptionKeys]: OptionRequirement; // здесь используется синтаксис key in
}
В этом примере мы создаем перечисление Option
для определения возможных значений. Затем мы используем keyof
для получения ключей этого перечисления, чтобы создать тип OptionKeys
.
С помощью синтаксиса отображаемого типа мы объявляем OptionRequirements
, который будет объектом, где каждый ключ соответствует значению из Option
, а значением является объект типа OptionRequirement
. Это позволяет избежать использования интерфейса и делает код более декларативным и читабельным.
Как преобразовать строку в число в TypeScript?
Возможно ли расширять типы в TypeScript?
Когда использовать JSX.Element, ReactNode и ReactElement?
Переопределение типа свойства интерфейса, определённого в файле d.ts TypeScript
Как проверить, содержит ли массив строку в TypeScript?