首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类型中缺少索引签名。

类型中缺少索引签名。
EN

Stack Overflow用户
提问于 2018-11-26 13:54:05
回答 2查看 5.9K关注 0票数 1

我正在尝试创建一个类型EventEmitter,但是我不能强制要求传递给泛型的接口是EventMap类型的,而没有TypeScript的抱怨。

代码语言:javascript
复制
type EventHandler = () => void
type EventMap = Record<string, EventHandler>

interface EventListener {
  handler: EventHandler
  once: boolean
}

export class Emitter<Events extends EventMap> {
  private listeners = new Map<keyof Events, EventListener[]>()

  private addListener<E extends keyof EventMap>(type: E, listener: EventListener) {
    const listeners = this.listeners.get(type) || []
    this.listeners.set(type, [...listeners, listener])
  }

  @bind
  public on<E extends keyof EventMap>(type: E, handler: Events[E]) {
    this.addListener(type, { handler, once: false })
  }
}


interface TestEvents {
  test: (a: number) => void,
}

class Test extends Emitter<TestEvents> {}

给我

代码语言:javascript
复制
Type 'TestEvents' does not satisfy the constraint 'Record<string, EventHandler>'.
Index signature is missing in type 'TestEvents'.
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-11-26 14:29:49

您需要对其进行稍微不同的约束,您希望Events的所有键都是EventHandlers,而Events不一定要有索引签名。您可以使用以下内容:

代码语言:javascript
复制
type EventHandler = (...a: any[]) => void

interface EventListener {
    handler: EventHandler
    once: boolean
}

export class Emitter<Events extends Record<keyof Events, EventHandler>> {
    private listeners = new Map<keyof Events, EventListener[]>()

    private addListener<E extends keyof Events>(type: E, listener: EventListener) {
        const listeners = this.listeners.get(type) || []
        this.listeners.set(type, [...listeners, listener])
    }

    public on<E extends keyof Events>(type: E, handler: Events[E]) {
        this.addListener(type, { handler, once: false })
    }
}


interface TestEvents {
    test: (a: number) => void,
}

class Test extends Emitter<TestEvents> { }
new Test().on("test", a => a.toExponential) // a is number.

但是,这种方法存在一个问题,如果地图中有多个事件(可能会有),类型记录将无法推断参数类型。

代码语言:javascript
复制
interface TestEvents {
    test: (a: number) => void,
    test2: (a: number) => void,
}

class Test extends Emitter<TestEvents> { }
new Test().on("test", a => a.toExponential) // a is any

这是可以修复的,但是类型变得更加复杂,请参阅here获得一个非常类似的想法。

票数 5
EN

Stack Overflow用户

发布于 2018-11-26 14:07:15

因为Record是:

代码语言:javascript
复制
type Record<K extends string, T> = {
    [P in K]: T;
}

您缺少定义的索引:

代码语言:javascript
复制
interface TestEvents {
    test: () => void;
    [index: string] : EventHandler;
}

而且,您的测试方法是无效的,因为它不符合EventHandler的要求,不强制该方法上的任何参数。

这个怎么样:

代码语言:javascript
复制
export interface EventMap extends Record<string, EventHandler>{
    [index: string]: EventHandler;
    event1: () => void;
    event2: () => void;
}

现在存在所需的索引器,但您强制类拥有event1event2

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

https://stackoverflow.com/questions/53482637

复制
相关文章

相似问题

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