类型中缺少索引签名
Posted
技术标签:
【中文标题】类型中缺少索引签名【英文标题】:Index signature is missing in type 【发布时间】:2019-04-28 04:30:57 【问题描述】:我正在尝试创建一个类型安全的 EventEmitter,但是我无法强制传递给泛型的接口是 EventMap
类型而没有 TypeScript 抱怨。
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>
给我
Type 'TestEvents' does not satisfy the constraint 'Record<string, EventHandler>'.
Index signature is missing in type 'TestEvents'.
【问题讨论】:
请提供Record<,>
类型的定义是否需要索引器?类似:[index:string] : string
Record
是 TypeScript 中的内置类型。编辑:***.com/questions/51936369/…
【参考方案1】:
您需要对其进行稍微不同的约束,您希望Events
的所有键都为EventHandlers
,而Events
不一定具有索引签名。您可以使用以下内容:
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.
但是,这种方法存在问题,如果您在地图中有多个事件(您可能会这样做),打字稿将无法推断出参数类型
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 以获得非常相似的想法。
【讨论】:
所以,我最终使我的发射器与传统的 node.js 发射器有点不同,方法是使用extends object
并使我的地图类型表示单个值而不是多个参数。不过谢谢你的回答。【参考方案2】:
由于Record
是:
type Record<K extends string, T> =
[P in K]: T;
您缺少定义的索引:
interface TestEvents
test: () => void;
[index: string] : EventHandler;
您的测试方法也是无效的,因为它不符合 EventHandler 要求,该要求不强制该方法上没有参数。
这个怎么样:
export interface EventMap extends Record<string, EventHandler>
[index: string]: EventHandler;
event1: () => void;
event2: () => void;
现在所需的索引器已存在,但您强制类具有 event1
和 event2
。
【讨论】:
对,但这不是我需要的。在那里添加索引签名也不会使其类型安全,因为对可以发出和收听的事件没有限制。必须有一种方法可以正确地做到这一点。 这是您在问题中所要求的。 EventMap 只是一个带有索引字符串和 EventHandler 作为结果的记录,所以是 EventMap 被强制执行。以上是关于类型中缺少索引签名的主要内容,如果未能解决你的问题,请参考以下文章
Type 中缺少索引签名 - AngularJS + TypeScript 验证使用 $validators