Given the following code:
function SumSystem() {
return {
sum(x: number, y: number) {
return x y
}
}
}
function MultiplySystem() {
return {
multiply(x: number, y: number) {
return x * y
}
}
}
function emit<S extends () => Record<string, unknown>>(systems: S[]): { [K in keyof ReturnType<S>]: ReturnType<S>[K] } {
// whatever
return {}
}
emit([SumSystem]).sum(1, 2) // works
emit([MultiplySystem]).multiply(2, 2) // works
emit([SumSystem, MultiplySystem]).sum(1, 2) // does not work
emit([SumSystem, MultiplySystem]).multiply(2, 2) // does not work
As per comments, the last two emit
s are not working, and that's occurring because I am passing two values into the argument's array: [SumSystem, MultiplySystem]
.
Questions:
- What's the problem?
- Is it possible to fix it?
- If the second question is true, how?
CodePudding user response:
Use the generic to infer the type of the entire array instead, get the return type of all the functions, then turn that union into an intersection for the result.
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I)=>void) ? I : never
function emit<S extends (() => Record<string, unknown>)[]>(systems: S): UnionToIntersection<ReturnType<S[number]>> { ... }
Your solution does not work as intended because S
is inferred as (() => { sum... }) | (() => { multiply... })
instead of an array.