UNPKG

@msom/common

Version:

@msom/common

175 lines (157 loc) 4.22 kB
import { Collection } from "../collection"; import { defineProperty } from "../global"; import { assert } from "../assert"; const TYPE_SPLITOR = ","; const OVERlOAD_KEY = Symbol("overload"); const ADD_IMPLEMENT = "addImplement" as const; /** * TypeScript 基础类型的联合类型 */ type TSTypeUnion = | string | number | boolean | undefined | object | symbol | bigint | void; /** * TypeScript 类型到类型名称的映射 */ type TypeToName<T extends TSTypeUnion> = T extends string ? "string" : T extends number ? "number" : T extends boolean ? "boolean" : T extends undefined ? "undefined" : T extends (...args: unknown[]) => unknown ? "function" : T extends symbol ? "symbol" : T extends bigint ? "bigint" : T extends object ? "object" : T extends void ? "void" : never; /** * 获取除最后一个元素外的所有元素类型 */ type DropLast<T extends TSTypeUnion[]> = T extends [...infer Rest, unknown] ? Rest extends TSTypeUnion[] ? Rest : [] : []; /** * 获取数组的最后一个元素类型 */ type Last<T extends TSTypeUnion[]> = T extends [...unknown[], infer L] ? L extends TSTypeUnion ? L : never : never; type TSArrayToNameArray<T extends TSTypeUnion[]> = T extends [ infer R, ...infer Rest ] ? [ ...(R extends TSTypeUnion ? [TypeToName<R>] : []), ...(Rest extends TSTypeUnion[] ? TSArrayToNameArray<Rest> : []) ] : []; /** * 可重载函数的类型定义 */ type OverLoadableFunction<T extends TSTypeUnion[][]> = { (...args: DropLast<T[number]>): Last<T[number]>; [ADD_IMPLEMENT]: <U extends T[number]>( ...impl: [ ...TSArrayToNameArray<DropLast<U>>, (...args: DropLast<U>) => Last<U> ] ) => OverLoadableFunction<T>; }; type CreateOverloadImpls<T extends TSTypeUnion[][]> = { [K in keyof T]: T[K] extends TSTypeUnion[] ? [ ...TSArrayToNameArray<DropLast<T[K]>>, (...args: DropLast<T[K]>) => Last<T[K]> ] : never; }; // type CreateOverloadImpls<T extends TSTypeUnion[][]> = T extends [ // infer R, // ...infer Rest // ] // ? [ // ...(R extends TSTypeUnion[] // ? [ // [ // ...TSArrayToNameArray<DropLast<R>>, // (...args: DropLast<R>) => Last<R> // ] // ] // : []), // ...(Rest extends TSTypeUnion[][] ? CreateOverloadImpls<Rest> : []) // ] // : []; /** * 创建一个可重载的函数 * @template T 类型数组的数组,每个数组最后一个类型为返回值类型 */ export function createOverload<T extends TSTypeUnion[][]>( impls?: CreateOverloadImpls<T> ): OverLoadableFunction<T> { const overloadCollection = new Collection< <U extends T[number]>(...args: DropLast<U>) => Last<U> >((m) => { return Reflect.get(m, OVERlOAD_KEY) as string; }); const Method = { method<U extends T[number]>(...args: DropLast<U>): Last<U> { const overloadKey = args.map((v) => typeof v).join(TYPE_SPLITOR); const overload = overloadCollection.get(overloadKey); assert(overload, "No implementation found"); return overload.apply(this, args); }, add<U extends T[number]>(...impl: U) { const overload = impl.pop() as unknown as ( ...args: T[number] ) => Last<T[number]>; if (typeof overload !== "function") { throw Error("The last parameter must be a function"); } const overloadKey = impl.join(TYPE_SPLITOR); overloadCollection.addKey(overloadKey, overload, true); }, }; defineProperty(Method.method, ADD_IMPLEMENT, 0, Method.add); if (impls) { for (const impl of impls) { Method.add(...impl); } } return Method.method as OverLoadableFunction<T>; } /** * 使用示例 */ const example = createOverload< [[string, number, number], [string, string], [number, number]] >([ ["string", "number", (a: string, c: number = 1) => Number(a) + c], ["string", (a: string) => a], ["number", (a: number) => a], ]); example("1", 2); example("1"); example(1); example[ADD_IMPLEMENT]<[string, number, number]>( "string", "number", (a: string, c: number = 1) => Number(a) + c );