TypeScript: генерировать тип или интерфейс значений перечисления - PullRequest
2 голосов
/ 07 мая 2019

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

У меня есть enum с потенциально большим количеством пар ключ-значение.Каждое из значений перечисления используется в качестве идентификатора формы, поэтому я получаю имя и значение элемента input в прослушивателе событий.Я хотел бы установить состояние на 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 handleChange = (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 в нашем проекте

Ответы [ 3 ]

1 голос
/ 07 мая 2019

Вам необходимо использовать interasection и сопоставленный тип (предопределенный 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]: ''
        }
    }
}
1 голос
/ 07 мая 2019

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

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

Тогда

type IMyReactComponentState = InputValues & {
    alreadyExisting: boolean
};

Или:

interface IMyReactComponentState extends InputValues {
    alreadyExisting: boolean
}
0 голосов
/ 07 мая 2019

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

interface IMyReactComponentState {
    alreadyExisting: boolean;
    [key in keyof typeof InputIDs]: string 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...