6

Параметр типа подписки индекса не может быть объединенным типом. Рассмотрите возможность использования типизированного объекта вместо этого!

13

Я пытаюсь использовать следующий паттерн:

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 ответ(ов)

2

Самое простое решение — использовать Record:

type OptionRequirements = Record<Options, OptionRequirement>;

Вы также можете реализовать это самостоятельно следующим образом:

type OptionRequirements = {
  [key in Options]: OptionRequirement;
}

Этот конструкция доступна только для type, но не для interface.

Проблема в вашем определении заключается в том, что вы указываете, что ключ вашего интерфейса должен быть типа Options, в то время как Options является перечислением, а не строкой, числом или символом.

key in Options означает "для тех специфических ключей, которые находятся в объединенном типе Options".

Псевдоним type более гибок и мощен по сравнению с interface.

Если ваш тип не нужно использовать в классе, выбирайте type вместо interface.

1

В вашем случае проблема заключалась в использовании двоеточия : в определении типа для ключей в объекте. Это вызывало ошибку. Чтобы исправить это, вы можете использовать оператор in, который позволяет корректно задать типы для ключей.

Вот исправленный код:

export type PossibleKeysType =
  | 'userAgreement'
  | 'privacy'
  | 'people';

interface ProviderProps {
  children: React.ReactNode;
  items: {
    //     ↙ используйте оператор "in"
    [key in PossibleKeysType]: Array<SectionItemsType>;
  };
}

Таким образом, если вы замените : на in, ваш интерфейс будет корректно определять ключи, и это решит возникшую проблему.

0

У меня была похожая проблема, но в моем случае это касалось другого свойства интерфейса. В качестве примера, вот мое решение с необязательным свойством поля и перечислением для ключей:

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, являются необязательными, поэтому вы можете работать с частичными данными.

0

В вашем случае, если вам нужно, чтобы свойства были опциональными, вы можете создать следующий обобщенный тип:

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.

0

Вместо использования интерфейса, можно применить тип отображаемого объекта. Вот пример, как это можно сделать:

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. Это позволяет избежать использования интерфейса и делает код более декларативным и читабельным.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь