Определить сигнатуру функции машинописного текста из объединения типов

Я хочу определить тип функции из объединения типов:

type MyEvent =
| { type: 'hello', payload: {} }
| { type: 'start', payload: { date: Date } }


type On<Event> = Event extends { type: infer EventType, payload: infer EventPayload }
  ? (type: EventType, callback: (payload: EventPayload) => void) => void
  : never

const on: On<MyEvent>
on('hello', (payload) => void)

но компилятор определяет тип первого аргумента как never

On возвращает тип, который кажется хорошим. Я также попробовал возвращаемый необработанный тип с тем же результатом:

type RawOn =
| ((type: "hello", callback: (payload: {}) => void) => void)
| ((type: "start", callback: (payload: { date: Date }) => void) => void)

const raw_on: RawOn
raw_on('hello', (payload) => void)

Как я могу определить тип объединения сигнатуры функции?

Playground


person Frédéric Mascaro    schedule 21.09.2020    source источник


Ответы (1)


Спасибо @cherryblossom за решение:

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void)
  ? I
  : never

// --------------------------------------------------
  
type MyEvent =
| { type: 'hello', payload: {} }
| { type: 'start', payload: { date: Date } }


type On<Event> = UnionToIntersection<
  Event extends { type: infer EventType, payload: infer EventPayload }
    ? (type: EventType, callback: (payload: EventPayload) => void) => void
    : never
>

const init_on = (): On<MyEvent> => {}
const on = init_on()

// OK
on('hello', (payload: {}) => {})
on('start', (payload: { date: Date }) => {})

// ERROR (that is OK)
on('hello', (payload: { date: Date }) => {})
on('bad-event', (payload: {}) => {})

Playground

person Frédéric Mascaro    schedule 21.09.2020