Я хотел бы, чтобы интерфейс был сгенерирован из значений перечисления. У меня есть следующий вариант использования в 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 в нашем проекте.






Вы можете определить свой IMyReactComponentState как
interface IMyReactComponentState {
alreadyExisting: boolean;
[key in keyof typeof InputIDs]: string
}
Вам нужно использовать пересечение и сопоставленный тип (подойдет предопределенный 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
}
Спасибо за ваш быстрый ответ. то я получаю следующую ошибку
']' expected.ts(1005) unused expression, expected an assignment or function calltslint(no-unused-expression)(я добавил точку с запятой во второй строке интерфейса, хотя я думаю, что в последнем определении они не нужны)