1
1
import { serial , flatHooks , mergeHooks } from './utils'
2
- import { LoggerT , hookFnT , configHooksT , deprecatedHookT , deprecatedHooksT } from './types'
2
+ import type { LoggerT , DeprecatedHook , NestedHooks , HookCallback , HookKeys } from './types'
3
3
export * from './types'
4
4
5
- class Hookable {
6
- private _hooks : { [ name : string ] : hookFnT [ ] }
7
- private _deprecatedHooks : deprecatedHooksT
5
+ class Hookable <
6
+ _HooksT = Record < string , HookCallback > ,
7
+ HooksT = _HooksT & { error : ( error : Error | any ) => void } ,
8
+ HookNameT extends HookKeys < HooksT > = HookKeys < HooksT >
9
+ > {
10
+ private _hooks : { [ key : string ] : HookCallback [ ] }
11
+ private _deprecatedHooks : Record < string , DeprecatedHook < HooksT > >
8
12
private _logger : LoggerT | false
9
13
10
14
static mergeHooks : typeof mergeHooks
@@ -20,7 +24,7 @@ class Hookable {
20
24
this . callHook = this . callHook . bind ( this )
21
25
}
22
26
23
- hook ( name : string , fn : hookFnT ) {
27
+ hook < NameT extends HookNameT > ( name : NameT , fn : HooksT [ NameT ] & HookCallback ) {
24
28
if ( ! name || typeof fn !== 'function' ) {
25
29
return ( ) => { }
26
30
}
@@ -56,19 +60,19 @@ class Hookable {
56
60
}
57
61
}
58
62
59
- hookOnce ( name : string , fn : hookFnT ) {
63
+ hookOnce < NameT extends HookNameT > ( name : NameT , fn : HooksT [ NameT ] & HookCallback ) {
60
64
let _unreg
61
65
let _fn = ( ...args ) => {
62
66
_unreg ( )
63
67
_unreg = null
64
68
_fn = null
65
69
return fn ( ...args )
66
70
}
67
- _unreg = this . hook ( name , _fn )
71
+ _unreg = this . hook ( name , _fn as typeof fn )
68
72
return _unreg
69
73
}
70
74
71
- removeHook ( name : string , fn : hookFnT ) {
75
+ removeHook < NameT extends HookNameT > ( name : NameT , fn : HooksT [ NameT ] & HookCallback ) {
72
76
if ( this . _hooks [ name ] ) {
73
77
const idx = this . _hooks [ name ] . indexOf ( fn )
74
78
@@ -82,16 +86,17 @@ class Hookable {
82
86
}
83
87
}
84
88
85
- deprecateHook ( name : string , deprecated : deprecatedHookT ) {
89
+ deprecateHook < NameT extends HookNameT > ( name : NameT , deprecated : DeprecatedHook < HooksT > ) {
86
90
this . _deprecatedHooks [ name ] = deprecated
87
91
}
88
92
89
- deprecateHooks ( deprecatedHooks : deprecatedHooksT ) {
93
+ deprecateHooks ( deprecatedHooks : Record < HookNameT , DeprecatedHook < HooksT > > ) {
90
94
Object . assign ( this . _deprecatedHooks , deprecatedHooks )
91
95
}
92
96
93
- addHooks ( configHooks : configHooksT ) {
94
- const hooks = flatHooks ( configHooks )
97
+ addHooks ( configHooks : NestedHooks < HooksT > ) {
98
+ const hooks = flatHooks < HooksT > ( configHooks )
99
+ // @ts -ignore
95
100
const removeFns = Object . keys ( hooks ) . map ( key => this . hook ( key , hooks [ key ] ) )
96
101
97
102
return ( ) => {
@@ -101,21 +106,24 @@ class Hookable {
101
106
}
102
107
}
103
108
104
- removeHooks ( configHooks : configHooksT ) {
105
- const hooks = flatHooks ( configHooks )
109
+ removeHooks ( configHooks : NestedHooks < HooksT > ) {
110
+ const hooks = flatHooks < HooksT > ( configHooks )
106
111
for ( const key in hooks ) {
112
+ // @ts -ignore
107
113
this . removeHook ( key , hooks [ key ] )
108
114
}
109
115
}
110
116
111
- async callHook ( name : string , ...args : any ) {
117
+ // @ts -ignore HooksT[NameT] & HookCallback prevents typechecking
118
+ async callHook < NameT extends HookNameT > ( name : NameT , ...args : Parameters < HooksT [ NameT ] > ) {
112
119
if ( ! this . _hooks [ name ] ) {
113
120
return
114
121
}
115
122
try {
116
123
await serial ( this . _hooks [ name ] , fn => fn ( ...args ) )
117
124
} catch ( err ) {
118
125
if ( name !== 'error' ) {
126
+ // @ts -ignore Stranger Things
119
127
await this . callHook ( 'error' , err )
120
128
}
121
129
if ( this . _logger ) {
0 commit comments