11import { serial , flatHooks , mergeHooks } from './utils'
2- import { LoggerT , hookFnT , configHooksT , deprecatedHookT , deprecatedHooksT } from './types'
2+ import type { LoggerT , DeprecatedHook , NestedHooks , HookCallback , HookKeys } from './types'
33export * from './types'
44
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 > >
812 private _logger : LoggerT | false
913
1014 static mergeHooks : typeof mergeHooks
@@ -20,7 +24,7 @@ class Hookable {
2024 this . callHook = this . callHook . bind ( this )
2125 }
2226
23- hook ( name : string , fn : hookFnT ) {
27+ hook < NameT extends HookNameT > ( name : NameT , fn : HooksT [ NameT ] & HookCallback ) {
2428 if ( ! name || typeof fn !== 'function' ) {
2529 return ( ) => { }
2630 }
@@ -56,19 +60,19 @@ class Hookable {
5660 }
5761 }
5862
59- hookOnce ( name : string , fn : hookFnT ) {
63+ hookOnce < NameT extends HookNameT > ( name : NameT , fn : HooksT [ NameT ] & HookCallback ) {
6064 let _unreg
6165 let _fn = ( ...args ) => {
6266 _unreg ( )
6367 _unreg = null
6468 _fn = null
6569 return fn ( ...args )
6670 }
67- _unreg = this . hook ( name , _fn )
71+ _unreg = this . hook ( name , _fn as typeof fn )
6872 return _unreg
6973 }
7074
71- removeHook ( name : string , fn : hookFnT ) {
75+ removeHook < NameT extends HookNameT > ( name : NameT , fn : HooksT [ NameT ] & HookCallback ) {
7276 if ( this . _hooks [ name ] ) {
7377 const idx = this . _hooks [ name ] . indexOf ( fn )
7478
@@ -82,16 +86,17 @@ class Hookable {
8286 }
8387 }
8488
85- deprecateHook ( name : string , deprecated : deprecatedHookT ) {
89+ deprecateHook < NameT extends HookNameT > ( name : NameT , deprecated : DeprecatedHook < HooksT > ) {
8690 this . _deprecatedHooks [ name ] = deprecated
8791 }
8892
89- deprecateHooks ( deprecatedHooks : deprecatedHooksT ) {
93+ deprecateHooks ( deprecatedHooks : Record < HookNameT , DeprecatedHook < HooksT > > ) {
9094 Object . assign ( this . _deprecatedHooks , deprecatedHooks )
9195 }
9296
93- addHooks ( configHooks : configHooksT ) {
94- const hooks = flatHooks ( configHooks )
97+ addHooks ( configHooks : NestedHooks < HooksT > ) {
98+ const hooks = flatHooks < HooksT > ( configHooks )
99+ // @ts -ignore
95100 const removeFns = Object . keys ( hooks ) . map ( key => this . hook ( key , hooks [ key ] ) )
96101
97102 return ( ) => {
@@ -101,21 +106,24 @@ class Hookable {
101106 }
102107 }
103108
104- removeHooks ( configHooks : configHooksT ) {
105- const hooks = flatHooks ( configHooks )
109+ removeHooks ( configHooks : NestedHooks < HooksT > ) {
110+ const hooks = flatHooks < HooksT > ( configHooks )
106111 for ( const key in hooks ) {
112+ // @ts -ignore
107113 this . removeHook ( key , hooks [ key ] )
108114 }
109115 }
110116
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 ] > ) {
112119 if ( ! this . _hooks [ name ] ) {
113120 return
114121 }
115122 try {
116123 await serial ( this . _hooks [ name ] , fn => fn ( ...args ) )
117124 } catch ( err ) {
118125 if ( name !== 'error' ) {
126+ // @ts -ignore Stranger Things
119127 await this . callHook ( 'error' , err )
120128 }
121129 if ( this . _logger ) {
0 commit comments