novy-syndicate/experiments/i2.ts

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'); } });