Skip to content

Commit 3f06e0e

Browse files
committed
feat: full TypeScript support for plugin API
1 parent de99b94 commit 3f06e0e

File tree

2 files changed

+46
-10
lines changed

2 files changed

+46
-10
lines changed

src/index.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,18 @@ import { Collection, HookCollection } from "before-after-hook";
33
import { request } from "@octokit/request";
44
import { graphql, withCustomRequest } from "@octokit/graphql";
55

6-
import { OctokitOptions, Plugin, RequestParameters } from "./types";
6+
import {
7+
Constructor,
8+
OctokitOptions,
9+
OctokitPlugin,
10+
RequestParameters,
11+
ReturnTypeOf
12+
} from "./types";
713
import { VERSION } from "./version";
814
import { withAuthorizationPrefix } from "./auth";
915

16+
export { OctokitOptions } from "./types";
17+
1018
export class Octokit {
1119
static defaults(defaults: OctokitOptions) {
1220
return class OctokitWithDefaults extends this {
@@ -20,16 +28,20 @@ export class Octokit {
2028
};
2129
}
2230

23-
static plugins: Plugin[] = [];
24-
static plugin(plugins: Plugin | Plugin[]) {
31+
static plugins: OctokitPlugin[] = [];
32+
static plugin<T extends OctokitPlugin | OctokitPlugin[]>(pluginOrPlugins: T) {
2533
const currentPlugins = this.plugins;
26-
const newPlugins = Array.isArray(plugins) ? plugins : [plugins];
34+
const newPlugins = Array.isArray(pluginOrPlugins)
35+
? pluginOrPlugins
36+
: [pluginOrPlugins];
2737

28-
return class NewOctokit extends this {
38+
const NewOctokit = class extends this {
2939
static plugins = currentPlugins.concat(
3040
newPlugins.filter(plugin => !currentPlugins.includes(plugin))
3141
);
3242
};
43+
44+
return NewOctokit as typeof NewOctokit & Constructor<ReturnTypeOf<T>>;
3345
}
3446

3547
constructor(options: OctokitOptions = {}) {
@@ -93,7 +105,9 @@ export class Octokit {
93105
// apply plugins
94106
// https://stackoverflow.com/a/16345172
95107
const classConstructor = this.constructor as typeof Octokit;
96-
classConstructor.plugins.forEach(plugin => plugin(this, options));
108+
classConstructor.plugins.forEach(plugin => {
109+
Object.assign(this, plugin(this, options));
110+
});
97111
}
98112

99113
// assigned during constructor
@@ -107,7 +121,4 @@ export class Octokit {
107121
[key: string]: any;
108122
};
109123
hook: HookCollection;
110-
111-
// allow for plugins to extend the Octokit instance
112-
[key: string]: any;
113124
}

src/types.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,29 @@ export type OctokitOptions = {
1111
[option: string]: any;
1212
};
1313

14-
export type Plugin = (octokit: Octokit, options: OctokitOptions) => void;
14+
export type Constructor<T> = new (...args: any[]) => T;
15+
16+
export type ReturnTypeOf<
17+
T extends AnyFunction | AnyFunction[]
18+
> = T extends AnyFunction
19+
? ReturnType<T>
20+
: T extends AnyFunction[]
21+
? UnionToIntersection<ReturnType<T[number]>>
22+
: never;
23+
24+
/**
25+
* @author https://stackoverflow.com/users/2887218/jcalz
26+
* @see https://stackoverflow.com/a/50375286/10325032
27+
*/
28+
type UnionToIntersection<Union> = (Union extends any
29+
? (argument: Union) => void
30+
: never) extends (argument: infer Intersection) => void // tslint:disable-line: no-unused
31+
? Intersection
32+
: never;
33+
34+
type AnyFunction = (...args: any) => any;
35+
36+
export type OctokitPlugin = (
37+
octokit: Octokit,
38+
options: OctokitOptions
39+
) => { [key: string]: any } | void;

0 commit comments

Comments
 (0)