
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
static-emitter
Advanced tools
EventTarget with support for static type enforcement of events.
The default event target allows for any string as the event name, and the data as Event. So knowing/using type information is impossible without extra (unnecessary) validations, or manual casting (risky).
StaticEmitter is a wrapper of EventTarget that enforces event format via static type declarations. It also supports non-Event bodies, symbol events, and NodeJS-esque syntax (on(), emit()...).
A type-only wrapper of EventTarget is also available, StaticEventTarget.
StaticEmitter works in both NodeJS and the browser.
npm i static-emitter
import { type events, StaticEmitter } from 'static-emitter';
class MyEmitter extends StaticEmitter {
declare public [events]: {
foo: [boolean, number[]];
bar: [string];
}
}
const myEmitter = new StaticEmitter<{
foo: number[];
bar: string;
}>();
myEmitter.on('foo', nums => {
console.log(nums); // typed as number[]
});
myEmitter.emit('foo', [123]); // success!
myEmitter.emit('bar', { wrong: null }); // Typescript error!
static-emitter is an ESM module. That means it must be imported. To load from a CJS module, use dynamic import const { StaticEmitter, StaticEventTarget } = await import('static-emitter');.
The StaticEventTarget is a type-cast of EventTarget. It provides no extra functionality in javascript-land. Therefore, it is highly recommended this class be used in Typescript to gain any benefit from static typing. It may be loaded separately via import { StaticEventTarget } from 'static-emitter/static-event-target';.
The StaticEmitter is an extension of StaticEventTarget. It includes support for symbol events, non-event bodies, and EventEmitter-esque syntax.
Type-only casting of Event. Includes a generic parameter for setting the eventName.
This casting may be convenient for usage with raw StaticEventTarget.
import { TypedEvent } from 'static-emitter';
// Or solo
import { TypedEvent } from 'static-emitter/typed-event';
const myEvent: TypedEvent<'abc'> = new TypedEvent('abc');
On Browser type-only casting of CustomEvent. Extends TypedEvent and includes an additional generic parameter for setting the detail. For non-null details, the detail option will be required.
On NodeJS a polyfill for CustomEvent, which does not natively exists.
import { CustomEvent } from 'static-emitter';
// Or solo
import { CustomEvent } from 'static-emitter/custom-event';
const myEvent: CustomEvent<'abc', 123> = new TypedEvent('abc', { detail: 123 });
const myNullEvent: CustomEvent<'foo', null> = new TypedEvent('foo');
A type-only symbol for declaring events on emitter extension. Not strictly required if event declarations only occur via generic parameters.
Note that events does not exist in javascript, and should only be used for event declarations.
Ensure any usage is paired with the typeof or declare keywords.
A type-only extension of EventTarget. Events can be declared which enforce the allowed dispatch/listener events.
Events can be declared via generic parameters (recommended when instantiating/extending an EventTarget directly) or via the events property.
Events are declared as a key-value mapping of eventName and eventDetail.
When eventDetail is an Event-extension (e.g. MouseEvent) then the detail is left unchanged. When any other type, it is wrapped in a CustomEvent.
import { CustomEvent, events, StaticEventTarget } from 'static-emitter';
// Or solo
import { StaticEventTarget } from 'static-emitter/static-event-target';
class MyTarget extends StaticEventTarget<{
click: MouseEvent;
}> {}
class MyExtendedTarget extends MyTarget {
[events]: MyTarget[events] & {
foo: 'bar';
}
}
const myTarget = new MyExtendedTarget();
// Alternative
const myTarget = new StaticEventTarget<{
click: MouseEvent;
foo: 'bar';
}>();
myTarget.addEventListener('click', (mouseEvent: MouseEvent) => {...});
myTarget.addEventListener('foo', {
handleEvent: (mouseEvent: CustomEvent<'foo', 'bar'>) => {...}),
});
// Typescript Error! Type mismatch.
myTarget.addEventListener('foo', (numEvent: CustomEvent<'foo', number>) => {...});
myTarget.dispatchEvent(new CustomEvent('foo', { detail: 'bar' }));
myTarget.dispatchEvent(new MouseEvent('click'));
Extension of StaticEventTarget with support for symbol events, non-event bodies, and EventEmitter-esque syntax.
The event declaration syntax of StaticEmitter is the same as StaticEventTarget, and any native events can be used the same way.
Note that symbol events and non-event bodies cannot use the native EventTarget methods.
Similarly, any non-CustomEvent events cannot use the helper methods and must rely on EventTarget's native methods (type constraints will still be applied). The exception is off() which supports all event names/listeners.
Listener methods (on + addListener) will pass two parameters. The first is the parsed detail from the custom event, and the raw CustomEvent as the second parameter.
import { CustomEvent, StaticEmitter } from 'static-emitter';
const serverConnect = Symbol('server-connect');
const myTarget = new StaticEmitter<{
click: MouseEvent;
foo: 'bar';
[serverConnect]: { port: number; timestamp: Date };
}>();
myTarget.on('foo', (bar: 'bar', nativeEvent: CustomEvent<'foo', 'bar'>) => {});
// Alias for `on()`
myTarget.addListener(serverConnect, (connectionDetails: { port: number; timestamp: Date }) => {});
// Typescript Error! Type mismatch.
myTarget.on('foo', (num: number) => {});
// Typescript Error! Native MouseEvent not supported.
myTarget.on('click', (mouseEvent: MouseEvent) => {});
// Remove listener immediately after first event
myTarget.once('foo', (bar: 'bar') => {});
myTarget.emit('foo', 'bar');
myTarget.emit(serverConnect, { port: 3000, timestamp: new Date() });
// Typescript Error! Type mismatch.
myTarget.emit('foo', 123);
// Example only, note this wouldn't actually "remove" anything, as this function was never added.
myTarget.off(serverConnect, () => {})
// Alias for `off()`. Supports native format.
myTarget.removeListener('foo', {
handleEvent: (customEvent: CustomEvent<'foo', 'bar'>) => {},
});
// Supports native events
myTarget.off('click', (mouseEvent: MouseEvent) => {});
FAQs
Statically typed event emitter.
The npm package static-emitter receives a total of 29 weekly downloads. As such, static-emitter popularity was classified as not popular.
We found that static-emitter demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.