TypeScript позволяет типизировать собственные события, чтобы гарантировать корректную работу с их объектами, особенно в веб-приложениях или при работе с паттерном pub/sub. Для типизации событий часто используют тип CustomEvent с параметизированным generic-типом:
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); });
Ключевые нюансы:
CustomEvent<T>) совпадает как при создании события, так и при его обработке.any или object.Часто спрашивают: «Можно ли типизировать объект event напрямую как
CustomEvent<Type>в обработчике, если событие создаёт сторонняя библиотека?»
Правильный ответ: Только если абсолютно точно известно, что библиотека генерирует события через CustomEvent с дженериком. Иначе типизация будет некорректной, возможны runtime-ошибки.
Пример:
document.addEventListener('some-event', (e: Event) => { // Ошибочно: 'e' не обязательно CustomEvent const detail = (e as CustomEvent<{ id: number }>).detail; // Это приведёт к ошибке, если событие не CustomEvent });
История
На проекте использовали абстракцию pub/sub и бросали события через простой Event вместо CustomEvent. Ожидали, что можно будет обращаться к event.detail, но у базового Event такого поля нет, что привело к бесшумному undefined и трудноуловимым багам.
История
Часть команды типизировала кастомные события через any, чтобы "быстрее" внедрить обработчики на разные сценарии. В результате, позже стали возникать ошибки из-за передачи разных структур данных через detail, а TypeScript не сигнализировал о несоответствиях.
История
В одном проекте стали использовать типизацию событий как CustomEvent<string>, передавая при этом сложные объекты через detail. По ошибке сериализовали detail, что приводило к необходимости делать дополнительный JSON.parse на стороне обработчика и к утрате типизации внутри TypeScript.