我有以下工作代码,没有类型错误:
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 ) {}
(example on 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中,我可以创建类似枚举的对象,而不必求助于一些不太枯燥的东西,比如
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 ) {}
(Playground link
因此,我的问题是:有没有一种方法可以让我编写此代码,以便每次只指定一次事件以及有效负载类型?
如果每个事件名称只有一个实例不可能做到这一点,那么最好的方法是什么?
发布于 2018-11-30 07:52:44
我找到了一种方法,使得每个事件名称只定义一次,使用一个保存类型信息并生成JS输出的虚拟类,我们可以迭代这些输出,以便通过正确的类型创建类似枚举的对象:
class EventTypes {
constructor(
// define a map of event names to event payload types here.
public SOME_EVENT: number,
public OTHER_EVENT: string
) {}
}
const EventNames = {} as { [k in keyof EventTypes]: k }
for (const key in new (EventTypes as any)) {
EventNames[key] = key
}
console.log(EventNames)
interface EventEmitter<EventTypes> {
on<K extends keyof EventTypes>(s: K, listener: (v: EventTypes[K]) => void);
}
declare const emitter: EventEmitter<EventTypes>;
emitter.on(EventNames.SOME_EVENT, (payload) => testNumber(payload));
emitter.on(EventNames.OTHER_EVENT, (payload) => testString(payload));
function testNumber( value: number ) { console.assert(typeof value === 'number') }
function testString( value: string ) { console.assert(typeof value === 'string') }
playground link
https://stackoverflow.com/questions/53548109
复制相似问题