import {reflect, CallSite} from 'typescript-rtti' type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; export default function overload( imps: T, callSite?: CallSite): UnionToIntersection { const impTypes = reflect(callSite).parameters[0].elements return ((...a: any[]) => { for (let i = 0; i < imps.length; ++i) { const paramTypes = impTypes[i].type.parameters let match = true const haveArgs = a.length let onArg = 0 for (const param of paramTypes) { if (param.isRest) { // All the rest of the arguments must be of param's type match = a.slice(onArg).every( arg => param.type.matchesValue(arg)) break } if (onArg === haveArgs) { // We've used all of the arguments, so better be optional match = param.isOptional break } // This argument must match this param's type and both are used match = param.type.matchesValue(a[onArg]) onArg += 1 if (!match) break } // Make sure we used all the arguments match &&= (onArg == haveArgs) if (match) return imps[i](...a) } throw new TypeError( `Actual arguments ${a} of type ${a.map(arg => typeof arg)} ` + 'did not match any implementation') }) }