首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将字符串数组映射到键到类型的TypeScript类型映射?

如何将字符串数组映射到键到类型的TypeScript类型映射?
EN

Stack Overflow用户
提问于 2018-11-30 05:48:58
回答 1查看 2.2K关注 0票数 0

我有以下工作代码,没有类型错误:

代码语言:javascript
运行
复制
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的东西来实现类型名称的自动补全,这样我就可以编写类似以下内容的代码,而不是使用字符串文字:

代码语言:javascript
运行
复制
emitter.on(EventNames.SOME_EVENT, (payload) => testNumber(payload));
emitter.on(EventNames.OTHER_EVENT, (payload) => testString(payload));

我正在尝试保持干燥,所以我想知道是否有一种方法可以在不重复新类型中的所有事件名称的情况下使其工作。

在普通的JavaScript中,我可以轻松地完成以下操作:

代码语言: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中,我可以创建类似枚举的对象,而不必求助于一些不太枯燥的东西,比如

代码语言:javascript
运行
复制
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中保持尽可能少的东西,只定义每个事件的名称一次,而且还有一个与事件有效负载相关联的类型。

我可以用以下不太枯燥的方法来完成,每个事件名称重复三次:

代码语言:javascript
运行
复制
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

因此,我的问题是:有没有一种方法可以让我编写此代码,以便每次只指定一次事件以及有效负载类型?

如果每个事件名称只有一个实例不可能做到这一点,那么最好的方法是什么?

EN

回答 1

Stack Overflow用户

发布于 2018-11-30 07:52:44

我找到了一种方法,使得每个事件名称只定义一次,使用一个保存类型信息并生成JS输出的虚拟类,我们可以迭代这些输出,以便通过正确的类型创建类似枚举的对象:

代码语言:javascript
运行
复制
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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53548109

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档