Тип обработчиков из карты событий
Вопрос
Есть тип Events = { click: { x: number }; close: void }. Как вывести из него тип { onClick: (e: { x: number }) => void; onClose: (e: void) => void }?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Mapped-тип по `keyof Events`
Переназначение ключа через `as` и шаблонную строку `` `on${Capitalize<string & K>}` ``
Значение `(e: Events[K]) => void` через индексный доступ
`string & K` нужен, потому что `keyof` включает `number | symbol`
Один источник правды: добавил событие в карту, обработчик появился автоматически
Что могут спросить следом
- Как сделать все обработчики необязательными?
- Как обратно получить имя события из
onClick? - Как типизировать
emit(name, payload)на той же карте?
Разбор
Беру mapped-тип по ключам карты и переименовываю ключи: type Handlers = { [K in keyof Events as `on${Capitalize<string & K>}`]: (e: Events[K]) => void }. as с шаблонной строкой превращает click в onClick, а Events[K] подставляет тип полезной нагрузки. string & K нужен потому, что keyof в общем случае включает числа и символы, а Capitalize принимает только строки. Необязательными обработчики делаю добавлением ? после ключа. Обратная операция делается условным типом с infer: K extends `on${infer E}` ? Uncapitalize<E> : never. На той же карте типизируется и emit<K extends keyof Events>(name: K, payload: Events[K]). Плюс подхода в том, что карта событий одна, и всё остальное выводится из неё.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.