Jurijs Kovzels' answer is technically correct - all you have to do is extend the global DOM types.
But the implementation is a bit tedious: you will have to extend type of addEventListener(), removeEventListener() and dispatchEvent() for all types of elements (HTMLInputElement, HTMLDivElement, etc.)
Instead, I'd suggest to
Extend GlobalEventHandlersEventMap.
There are a couple of ways you can do it:
A) Declare it globally in a file of interest
This is a fast way to make sure everything works but I would not keep it in a production codebase.
declare global {
interface GlobalEventHandlersEventMap {
build: CustomEvent<number>;
}
}
B) Create your own .d.ts declaration file
You can do the same as above by writing your own file with global declarations
- Create a file
declarations/dom.d.ts and add the following in it
interface GlobalEventHandlersEventMap {
build: CustomEvent<number>;
}
- Then make sure it is included in your
tsconfig.json
{
"include": [
"declarations/*.d.ts",
],
}
- And it works! Now your listeners are properly typed

You can go further and add util for creating strictly typed events like this:
export const createTypedCustomEvent = <T extends CustomEventType>(
type: T,
eventInitDict: CustomEventInit<CustomEventHandlersMap[T]>,
) => new CustomEvent(type, eventInitDict);
Then you will be getting type hints and checks for the detail field:
Non existent event

Incorrect type of event detail
