TypeScript: создание типа или интерфейса значений перечисления

Я хотел бы, чтобы интерфейс был сгенерирован из значений перечисления. У меня есть следующий вариант использования в React:

У меня есть перечисление с потенциально большим количеством пар ключ-значение. Каждое из значений перечисления используется в качестве идентификатора формы, поэтому я получаю имя и значение элемента ввода в прослушивателе событий. Я бы хотел установить состояние this.setState({ name: value }), но имя, описание и т. д. должны быть типобезопасными.

Поэтому мне как-то нужно сгенерировать интерфейс из значений перечисления (поскольку интерфейс не может наследоваться от перечисления), чтобы иметь возможность делать, например, следующее: this.setState({ name: 'hello world' }) и this.setState({ description: 'a description' })

enum InputIDs {
    NAME = 'name',
    DESCRIPTION = 'description',
    // ... many more items ...
}

interface IMyReactComponentState {
    alreadyExisting: boolean;
    [InputIDs.NAME]: string;
    // ... all other items from the Test enum should go here but I'd like to generate it somehow ...
}

class MyReactComponent extends React.Component< ISomeProps, IMyReactComponentState > {
    constructor(props: ISomeProps) {
        super(props);
        this.state = {
            alreadyExisting: false,
            [InputIDs.NAME]: '',
            // more default values
        }
    }

    private handleChangeEvent = (event: React.FormEvent<HTMLDivElement>) => {
        // TODO make type safe
        const {name, value}: {name: any, value: string} = (event.target as any); // event.target is either HTMLInputElement, HTMLSelectElement or HTMLTextAreaElement

        // store the value of the corresponding input in state to preserve it when changing tabs
        this.setState({
            [name]: value
        });
  }

}

Моя проблема в том, что что-то в этом направлении невозможно:

interface IMyReactComponentState extends InputIDs {
    alreadyExisting: boolean;
}

Любые идеи, как я могу синхронизировать перечисление с типами IMyReactComponentState без написания интерфейса самостоятельно?

Заранее спасибо! Не уверен, что об этом уже спрашивали - если да, то я еще не нашел ответа!


РЕДАКТИРОВАТЬ (8 мая 2019 г.):

Мы используем TypeScript 2.8.1 в нашем проекте.

Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
2
0
3 726
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете определить свой IMyReactComponentState как

interface IMyReactComponentState {
    alreadyExisting: boolean;
    [key in keyof typeof InputIDs]: string 
}

Спасибо за ваш быстрый ответ. то я получаю следующую ошибку ']' expected.ts(1005) unused expression, expected an assignment or function calltslint(no-unused-expression) (я добавил точку с запятой во второй строке интерфейса, хотя я думаю, что в последнем определении они не нужны)

lehnerchristian 07.05.2019 11:20
Ответ принят как подходящий

Вам нужно использовать пересечение и сопоставленный тип (подойдет предопределенный Record сопоставленный тип)

enum InputIDs {
    NAME = 'name',
    DESCRIPTION = 'description',
    // ... many more items ...
}

type IMyReactComponentState = {
    alreadyExisting: boolean;
} & Record<InputIDs, string>

class MyReactComponent { // simplified
    state:IMyReactComponentState
    constructor() {        
        this.state = {
            alreadyExisting: false,
            [InputIDs.NAME]: '',
            [InputIDs.DESCRIPTION]: ''
        }
    }
}

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

type InputValues = {
    [key in InputIDs]: string
}

потом

type IMyReactComponentState = InputValues & {
    alreadyExisting: boolean
};

Или:

interface IMyReactComponentState extends InputValues {
    alreadyExisting: boolean
}

Другие вопросы по теме