Search code examples
typescripttypescript-genericstypescript-types

Merge return types of interface containing functions


Let's say we have an object containing some functions:

const handlers = {
  handler1: (state: State, payload: boolean) => ({
    schema: payload,
    errors: [],
  }),
  handler2: (state: State, payload: string[]) => ({
    errors: payload,
  }),
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  reset: (...args: any) => initialState,
}

I need to define a type that merges their return types like

State | {
  schema: boolean,
  errors: never[]
} | {
  errors: string[]
}

One simple solution could be

type MergeReturnTypes1 = ReturnType<typeof handlers[keyof typeof handlers]>

However I'm not getting why the following type definition

type MergeReturnType2<H> = H extends Record<string, (...args: any) => infer T> ? T : never

Is only return the return type of the first function contained in the handlers object

type T = MergeReturnType2<typeof handlers>

T = {
  schema: boolean
  errors: never[]
}

Solution

  • I am honestly not sure why this is not working but I'm still trying to figure out an explanation.

    You can fix the problem by using T to infer the whole function in the Record instead of only inferring the return type.

    type MergeReturnType2<H> = H extends Record<string, infer T extends (...args: any) => any> 
      ? ReturnType<T> 
      : never
    
    type T = MergeReturnType2<typeof handlers>
    
    // type T = State | {
    //     schema: boolean;
    //     errors: never[];
    // } | {
    //     errors: string[];
    // }
    

    Playground