【发布时间】:2018-11-29 21:48:58
【问题描述】:
我有以下工作代码,没有类型错误:
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 ) {}
但是,我想使用类似于 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 中,我可以创建类似枚举的对象,而不必诉诸一些不那么 DRY 的东西
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 中尽可能保持 DRY,只定义每个事件的名称一次,而且还有一个与事件有效负载相关联的类型。
我可以使用以下 less-DRY 方式,每次重复事件名称 3 次:
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 ) {}
所以我的问题是:有没有一种方法可以编写这个,以便我每次只指定一次事件以及有效负载类型?
如果不可能只使用每个事件名称的一个实例,那么最好的方法是什么?
【问题讨论】:
-
"自动完成类型名称" TypeScript 将在字符串文字中为您提供自动完成功能;你根本不需要那个。
-
您可以将纯 JS 解决方案与类型转换一起使用。
-
@SLaks 看起来怎么样?
-
const Events = {} as {[k in keyof Events]: k} -
但是我们如何将事件名称粘贴到空对象中,使其类似于枚举,而不在代码中重复事件名称?我找到了一种使用虚拟课程的方法(请参阅我的答案)。有没有更好的办法?我想也许这会有所帮助:gist.github.com/jcalz/381562d282ebaa9b41217d1b31e2c211