简体   繁体   中英

Type for intersection of all return types with list of functions

Say I have an array of functions like so:

const foo: Array< () => object > = [
    () => ({ one: 'fish' }),
    () => ({ two: 'fish' }),
    () => ({ red: 'fish' }),
    () => ({ blue: 'fish' })        
]

Is it possible to write a type that will intersection the return types of all these functions?

{
  one: string,
  two: string,
  red: string,
  blue: string,
}

Basically, the type for what would result if you reduced all these functions into a single result.

Interesting problem. This can be done using a combination of mapped types and conditional types; we need to:

  • Get rid of the type annotation Array<() => object> so that the array's actual contents can be used to construct a type,
  • Get the function types from the array type,
  • Get the return types of those function types,
  • That gives a union like {one: string} | {two: string} | {red: string} | {blue: string} {one: string} | {two: string} | {red: string} | {blue: string} {one: string} | {two: string} | {red: string} | {blue: string} so we need to be able to get the property names ( keyof doesn't work on a union like this),
  • Get the value type associated with a given property name in the union,
  • And finally, construct the result as a mapping from those property names to those value types.

Here's an implementation:

const foo = [
    () => ({ one: 'fish' }),
    () => ({ two: 'fish' }),
    () => ({ red: 'fish' }),
    () => ({ blue: 'fish' })
];

type ComponentType<A extends any[]> = A extends (infer U)[] ? U : never

type ReturnsUnion = ReturnType<ComponentType<typeof foo>>
// {one: string} | {two: string} | {red: string} | {blue: string}

type KeyOfUnion<T> = T extends infer U ? keyof U : never
// KeyOfUnion<ReturnsUnion> = 'one' | 'two' | 'red' | 'blue'

type ValueInUnion<T, K extends PropertyKey> = T extends { [k in K]: infer V } ? V : never

type Result = { [K in KeyOfUnion<ReturnsUnion>]: ValueInUnion<ReturnsUnion, K> }
// { one: string, two: string, red: string, blue: string }

Playground Link

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM