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:
Array<() => object>
so that the array's actual contents can be used to construct a type,{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),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 }