Я пытаюсь использовать следующий шаблон:
enum Option {
ONE = 'one',
TWO = 'two',
THREE = 'three'
}
interface OptionRequirement {
someBool: boolean;
someString: string;
}
interface OptionRequirements {
[key: Option]: OptionRequirement;
}
Мне это кажется очень простым, однако я получаю следующую ошибку:
Тип параметра подписи индекса не может быть типом объединения. Вместо этого рассмотрите возможность использования сопоставленного типа объекта.
Что я делаю не так?
javascript
typescript
Джон Маккарти
источник
источник
key
может быть только строкой, числом или символом. перечисление нет.Ответы:
Вы можете использовать оператор TS "in" и сделать это:
enum Options { ONE = 'one', TWO = 'two', THREE = 'three', } interface OptionRequirement { someBool: boolean; someString: string; } type OptionRequirements = { [key in Options]: OptionRequirement; // Note that "key in". }
источник
interface OptionRequirements
наtype OptionRequirements
Самое простое решение - использовать
Record
Вы также можете реализовать это самостоятельно как:
type OptionRequirements = { [key in Options]: OptionRequirement; }
Эта конструкция доступна только для
type
, но не доступнаinterface
.Проблема в вашем определении заключается в том, что ключ вашего интерфейса должен иметь тип
Options
, гдеOptions
это перечисление, а не строка, число или символ.В
key in Options
средства «для этих конкретных ключей , которые в параметрах типа союза».type
alias более гибкий и мощный, чемinterface
.Если ваш тип не должен использоваться в классе, выбрать
type
болееinterface
.источник
У меня была аналогичная проблема, но в моем случае было другое свойство поля в интерфейсе, поэтому мое решение в качестве примера с необязательным свойством поля с перечислением для ключей:
export enum ACTION_INSTANCE_KEY { cat = 'cat', dog = 'dog', cow = 'cow', book = 'book' } type ActionInstances = { [key in ACTION_INSTANCE_KEY]?: number; // cat id/dog id/cow id/ etc // <== optional }; export interface EventAnalyticsAction extends ActionInstances { // <== need to be extended marker: EVENT_ANALYTIC_ACTION_TYPE; // <== if you wanna add another field to interface }
источник
Вместо использования интерфейса используйте сопоставленный тип объекта
enum Option { ONE = 'one', TWO = 'two', THREE = 'three' } type OptionKeys = keyof typeof Option; interface OptionRequirement { someBool: boolean; someString: string; } type OptionRequirements = { // note type, not interface [key in OptionKeys]: OptionRequirement; // key in }
источник
В моем случае мне нужно было, чтобы свойства были необязательными, поэтому я создал этот универсальный тип.
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 } } }
источник
У меня была аналогичная проблема. Я пытался использовать только определенные ключи при создании валидаторов угловой формы.
export enum FormErrorEnum { unknown = 'unknown', customError = 'customError', } export type FormError = keyof typeof FormErrorEnum;
И использование:
static customFunction(param: number, param2: string): ValidatorFn { return (control: AbstractControl): { [key: FormErrorEnum]?: any } => { return { customError: {param, param2} }; }; }
Это позволит использовать 1 - X количество ключей.
источник