88 lines
3.5 KiB
TypeScript
88 lines
3.5 KiB
TypeScript
type ValidSelector = string | number | symbol
|
|
|
|
export type Message<Selector extends ValidSelector, Args extends any[], Result> =
|
|
Args extends never[]
|
|
? { selector: Selector, args: [], callback: (result: Result) => void }
|
|
: { selector: Selector, args: Args, callback: (result: Result) => void }
|
|
|
|
type MessagesProduct<I> = {
|
|
[K in keyof I]: (I[K] extends (...args: infer P) => infer Q ? Message<K, P, Q> : never);
|
|
}
|
|
|
|
export type Messages<I> = MessagesProduct<I>[keyof I]
|
|
|
|
export type Methods<M extends { selector: ValidSelector }> = {
|
|
[S in M['selector']]: (
|
|
M extends Message<S, infer P, infer R> ? (...args: P) => R :
|
|
never);
|
|
}
|
|
|
|
export function perform<I extends Methods<M>,
|
|
S extends ValidSelector,
|
|
M extends Message<S, any, any>>(
|
|
i: I,
|
|
m: M): void
|
|
{
|
|
m.callback(i[m.selector](... m.args));
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
interface I {
|
|
m1(a: string, b: number): boolean;
|
|
m2(): void;
|
|
m3(n: number): void;
|
|
m4(x: [string, string]): { k: string, j: string };
|
|
m5(a: string, b: string[]): number;
|
|
v: string;
|
|
w: number;
|
|
}
|
|
|
|
type M = Messages<I>
|
|
// type M =
|
|
// | Message<"m1", [a: string, b: number], boolean>
|
|
// | Message<"m2", [], void>
|
|
// | Message<"m3", [n: number], void>
|
|
// | Message<"m4", [x: [string, string]], { k: string; j: string }>
|
|
// | Message<"m5", [a: string, b: string[]], number>
|
|
// type M =
|
|
// | { selector: "m1", args: [a: string, b: number], callback: (result: boolean) => void }
|
|
// | { selector: "m2", args: [], callback: (result: void) => void }
|
|
// | { selector: "m3", args: [n: number], callback: (result: void) => void }
|
|
// | { selector: "m4", args: [x: [string, string]], callback: (result: { k: string; j: string }) => void }
|
|
// | { selector: "m5", args: [a: string, b: string[]], callback: (result: number) => void }
|
|
// type M =
|
|
// | { selector: "m1", args: [string, number], callback: (result: boolean) => void }
|
|
// | { selector: "m2", args: [], callback: (result: void) => void }
|
|
// | { selector: "m3", args: [number], callback: (result: void) => void }
|
|
// | { selector: "m4", args: [[string, string]], callback: (result: { k: string; j: string }) => void }
|
|
// | { selector: "m5", args: [string, string[]], callback: (result: number) => void }
|
|
|
|
type I2 = Methods<M>
|
|
// type I2 = {
|
|
// m1: (a: string, b: number) => boolean;
|
|
// m2: () => void;
|
|
// m3: (n: number) => void;
|
|
// m4: (x: [string, string]) => { k: string; j: string };
|
|
// m5: (a: string, b: string[]) => number;
|
|
// };
|
|
|
|
type X = I2
|
|
|
|
const a = {
|
|
a(): string { console.log('in a'); return 'hi'; },
|
|
b(): void { console.log('in b'); },
|
|
c(x: number): number { console.log('in c:', x); return x * 2; },
|
|
v(x: number, y: string, z: boolean): string { return `x ${x} y ${y} z ${z}`; },
|
|
};
|
|
type A = typeof a;
|
|
type A1 = Messages<A>;
|
|
type A2 = Methods<A1>;
|
|
const b: A2 = a;
|
|
|
|
const aa = perform(a, { selector: 'a', args: [], callback: (_r: string) => {} });
|
|
const bb = perform(a, { selector: 'b', args: [], callback: (_r: void) => { console.log('bb'); } });
|
|
const cc = perform(a, { selector: 'c', args: [123], callback: (r: number) => { console.log('cc', r); } });
|
|
const vv = perform(a, { selector: 'v', args: [123, 'hi', true], callback: (r: string) => { console.log('vv', r); } });
|
|
perform({ a(): string { return 'hi' } }, { selector: 'a', args: [123], callback: (_r: string) => { console.log('x'); } });
|