Let’s say I have this generic class interface:
export interface Base<E extends { [key: string | symbol]: () => void } = {}> extends EventEmitter {
Events: Record<string, keyof E>;
on(event: keyof E, cb: E[keyof E]): this;
once(event: keyof E, cb: E[keyof E]): this;
off(event: keyof E, cb: E[keyof E]): this;
emit(event: keyof E, ...args: Parameters<E[keyof E]>): boolean;
}
The idea here is to be able to define emitable events together with expected callback signature like this:
export enum HistoryEvents {
History = 'history',
}
interface HistoryEventsI {
[HistoryEvents.History]: (history: any) => void;
}
export interface History extends Base<HistoryEventsI> {
// ...
}
However I’m getting this error with such code:
Type HistoryEventsI does not satisfy the constraint
{
[key: string]: () => void;
[key: symbol]: () => void;
}
Index signature for type string is missing in type HistoryEvents
What am I doing wrong?
2
Answers
You have run into one of the differences b/w a type and interface.
The reason it is not working is because
HistoryEventsI
is not assignable to{ [key: string | symbol]: () => void }
.The below works (Have removed the extra argument):
HistoryEventsI
does not extendX
butHistoryEventsT
does.There is an issue on the repo discussing the same.
Basic idea is that it is not sure that the interface will always have a
string/symbol
as a key. New properties can be added to interfaces.Here is one of the most important replies from the above thread:
Playground for the workaround with types.
While it is true for JS objects the keys can only be string/symbol, but imagine you had another type which was like
{ a: 2, b: 2}
. Playground for referenceFirst thing you should update in your code is to update object mapping in interface
Base
:This updated code adds contraits to key and values of the generic parameter
E
, where each key must bestring
orsymbol
and values are functions that accept any amount of arguments with any type...args: []
.And secondly, I suggest you use a
type
keyword instead ofinterface
keyword to defineHistoryEventsI
because generic parameter ofBase
interface accepts anobject
. Using interface might cause some unexpected, unnecessary errors: