type Assign = { [K in keyof A | keyof B]: K extends keyof A ? K extends keyof B ? NonNullable extends (...args: any[]) => any ? NonNullable extends (...args: any[]) => any ? A[K] | B[K] : B[K] : B[K] : A[K] : K extends keyof B ? B[K] : never } type MergeObjectsArray = T extends [infer F, ...infer R] ? Assign : NonNullable> : NonNullable type PrettyObject = { [K in keyof T]: T[K] } & NonNullable export function chainEventHandlers< First extends Record, Rest extends Record[], >( first: First, ...rest: Rest ): PrettyObject> { const result: Record = { ...first } for (const obj of rest) { for (const key in obj) { const value = obj[key] const prev = result[key] if (typeof prev === 'function' && typeof value === 'function') { result[key] = (...args: any[]) => { prev(...args) return value(...args) } } else { result[key] = value } } } return result as MergeObjectsArray<[First, ...Rest]> }