Skip to content

Commit 4e4b38f

Browse files
committed
feat: initial version
1 parent 4b47731 commit 4e4b38f

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

index.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
type ApiExtension = { [key: string]: any };
2+
type TestPlugin = (instance: Base) => ApiExtension | undefined;
3+
type Constructor<T> = new (...args: any[]) => T;
4+
5+
/**
6+
* @author https://stackoverflow.com/users/2887218/jcalz
7+
* @see https://stackoverflow.com/a/50375286/10325032
8+
*/
9+
type UnionToIntersection<Union> = (Union extends any
10+
? (argument: Union) => void
11+
: never) extends (argument: infer Intersection) => void // tslint:disable-line: no-unused
12+
? Intersection
13+
: never;
14+
15+
type AnyFunction = (...args: any) => any;
16+
17+
type ReturnTypeOf<T extends AnyFunction | AnyFunction[]> = T extends AnyFunction
18+
? ReturnType<T>
19+
: T extends AnyFunction[]
20+
? UnionToIntersection<ReturnType<T[number]>>
21+
: never;
22+
23+
export class Base {
24+
static plugins: TestPlugin[] = [];
25+
static plugin<T extends TestPlugin | TestPlugin[]>(plugin: T) {
26+
const currentPlugins = this.plugins;
27+
28+
class NewTest extends this {
29+
static plugins = currentPlugins.concat(plugin);
30+
}
31+
32+
type Extension = ReturnTypeOf<T>;
33+
return NewTest as typeof NewTest & Constructor<Extension>;
34+
}
35+
36+
constructor() {
37+
// apply plugins
38+
// https://stackoverflow.com/a/16345172
39+
const classConstructor = this.constructor as typeof Base;
40+
classConstructor.plugins.forEach(plugin => {
41+
Object.assign(this, plugin(this));
42+
});
43+
}
44+
}

0 commit comments

Comments
 (0)