У меня есть следующий рабочий код без ошибок типа:
type Events = { SOME_EVENT: number; OTHER_EVENT: string }
interface EventEmitter<EventTypes> {
on<K extends keyof EventTypes>(s: K, listener: (v: EventTypes[K]) => void);
}
declare const emitter: EventEmitter<Events>;
emitter.on('SOME_EVENT', (payload) => testNumber(payload));
emitter.on('OTHER_EVENT', (payload) => testString(payload));
function testNumber( value: number ) {}
function testString( value: string ) {}
( пример на TS Playground )
Однако я бы хотелиспользуйте что-то похожее на enum
, чтобы иметь автозаполнение имен типов, чтобы я мог писать что-то вроде следующего вместо использования строковых литералов:
emitter.on(EventNames.SOME_EVENT, (payload) => testNumber(payload));
emitter.on(EventNames.OTHER_EVENT, (payload) => testString(payload));
Я пытаюсь сделать вещи СУХИМЫМИ, поэтому мне интересно, есть ли способ сделать эту работу без повторения всех имен событий в новом типе.
В простом JavaScript я могу легко сделать следующее:
const EventNames = [
'SOME_EVENT',
'OTHER_EVENT',
]
const Events = {}
for (const eventName of Events) {
Events[eventName] = eventName
}
// then use it:
emitter.on(Events.SOME_EVENT, (payload) => testNumber(payload));
emitter.on(Events.OTHER_EVENT, (payload) => testString(payload));
Таким образом, в простом JS я могу создавать объекты, похожие на enum, без необходимости прибегать к чему-то чуть менее СУХОМУ, например,
const Events = {
SOME_EVENT: 'SOME_EVENT', // repeats the names twice
OTHER_EVENT: 'OTHER_EVENT',
}
emitter.on(Events.SOME_EVENT, (payload) => testNumber(payload));
emitter.on(Events.OTHER_EVENT, (payload) => testString(payload));
Мне интересно, как я могу сделать вещи максимально сухими в TypeScript,только когда-либо определяя имя каждого события только один раз, но также имеет тип, связанный с полезными нагрузками события.
Я могу сделать это следующим способом менее СУХОЙ, повторяя имена событий три раза каждое:
type Events = { SOME_EVENT: number; OTHER_EVENT: string }
const EventNames: {[k in keyof Events]: k} = {
SOME_EVENT: 'SOME_EVENT', OTHER_EVENT: 'OTHER_EVENT'
}
interface EventEmitter<EventTypes> {
on<K extends keyof EventTypes>(s: K, listener: (v: EventTypes[K]) => void);
}
declare const emitter: EventEmitter<Events>;
emitter.on(EventNames.SOME_EVENT, (payload) => testNumber(payload));
emitter.on(EventNames.OTHER_EVENT, (payload) => testString(payload));
function testNumber( value: number ) {}
function testString( value: string ) {}
( Playgroи ссылка )
Итак, мой вопрос: есть ли способ, которым я могу написать это так, чтобы я указывал события только один раз каждый, а также типы полезной нагрузки?
Если это невозможно сделать только с одним экземпляром каждого имени события, каков наилучший способ?