ProgrammingFrontend Developer

How to implement typing for custom events in TypeScript? What nuances should be considered when working with event objects and data transmission?

Pass interviews with Hintsage AI assistant

Answer.

TypeScript allows typing of custom events to ensure correct handling of their objects, especially in web applications or when working with the pub/sub pattern. To type events, the CustomEvent type with a parameterized generic type is commonly used:

interface MyEventDetail { username: string; age: number; } const event = new CustomEvent<MyEventDetail>('user:create', { detail: { username: 'alice', age: 30 } }); document.addEventListener('user:create', (e: CustomEvent<MyEventDetail>) => { console.log(e.detail.username); });

Key nuances:

  • Make sure that the event type used (CustomEvent<T>) matches both when creating the event and when handling it.
  • If using a native event, use the basic event types instead of any or object.
  • Remember about event inheritance if you are creating your own types.

Trick Question.

Often asked: "Can the event object be directly typed as CustomEvent<Type> in the handler if the event is created by a third-party library?"

The correct answer: Only if it is absolutely certain that the library generates events via CustomEvent with a generic. Otherwise, typing will be incorrect, and runtime errors may occur.

Example:

document.addEventListener('some-event', (e: Event) => { // Incorrect: 'e' is not necessarily CustomEvent const detail = (e as CustomEvent<{ id: number }>).detail; // This will cause an error if the event is not CustomEvent });

Examples of real errors due to lack of knowledge on the topic.


Story

On the project, we used a pub/sub abstraction and emitted events through a plain Event instead of CustomEvent. We expected to access event.detail, but the base Event type does not have such a field, leading to silent undefined and subtle bugs.


Story

Part of the team typed custom events as any to implement handlers for various scenarios "faster". As a result, errors arose later due to passing different data structures via detail, and TypeScript did not signal any mismatches.


Story

In one project, they began using event typing as CustomEvent<string>, while passing complex objects via detail. They mistakenly serialized detail, leading to the need for additional JSON.parse on the handler side and loss of typing within TypeScript.