diff --git a/types/tapable/index.d.ts b/types/tapable/index.d.ts index 891279e0e5..d2cae7e6dc 100644 --- a/types/tapable/index.d.ts +++ b/types/tapable/index.d.ts @@ -245,31 +245,32 @@ export interface Tap { context: boolean; } -export class Hook { - constructor(...args: any[]); +export class Hook { + constructor(tapArgumentNames?: string[]); taps: any[]; interceptors: HookInterceptor[]; - call: (arg1?: T1, arg2?: T2, arg3?: T3, ...args: any[]) => any; - promise:(arg1?: T1, arg2?: T2, arg3?: T3, ...args: any[]) => Promise; - callAsync: (arg1?: T1, arg2?: T2, arg3?: T3, ...args: any[]) => any; + + call: (arg1?: TArg1, arg2?: TArg2, arg3?: TArg3, ...args: any[]) => THookResult; + promise:(arg1?: TArg1, arg2?: TArg2, arg3?: TArg3, ...args: any[]) => Promise; + callAsync: (arg1?: TArg1, arg2?: TArg2, arg3?: TArg3, ...args: any[]) => THookResult; compile(options: HookCompileOptions) : Function; - tap: (name: string | Tap, fn: (arg1: T1, arg2: T2, arg3: T3, ...args: any[]) => any) => void; - tapAsync: (name: string | Tap, fn: (arg1: T1, arg2: T2, arg3: T3, ...args: any[]) => void) => void; - tapPromise: (name: string | Tap, fn: (arg1: T1, arg2: T2, arg3: T3, ...args: any[]) => Promise) => void; + tap: (name: string | Tap, fn: (arg1: TArg1, arg2: TArg2, arg3: TArg3, ...args: any[]) => TTabResult) => void; + tapAsync: (name: string | Tap, fn: (arg1: TArg1, arg2: TArg2, arg3: TArg3, ...args: any[]) => void) => void; + tapPromise: (name: string | Tap, fn: (arg1: TArg1, arg2: TArg2, arg3: TArg3, ...args: any[]) => Promise) => void; intercept: (interceptor: HookInterceptor) => void; } -export class SyncHook extends Hook {} -export class SyncBailHook extends Hook {} -export class SyncLoopHook extends Hook {} -export class SyncWaterfallHook extends Hook {} +export class SyncHook extends Hook {} +export class SyncBailHook extends Hook {} +export class SyncLoopHook extends Hook {} +export class SyncWaterfallHook extends Hook {} -export class AsyncParallelHook extends Hook {} -export class AsyncParallelBailHook extends Hook {} -export class AsyncSeriesHook extends Hook {} -export class AsyncSeriesBailHook extends Hook {} -export class AsyncSeriesWaterfallHook extends Hook {} +export class AsyncParallelHook extends Hook {} +export class AsyncParallelBailHook extends Hook {} +export class AsyncSeriesHook extends Hook {} +export class AsyncSeriesBailHook extends Hook {} +export class AsyncSeriesWaterfallHook extends Hook {} export class HookInterceptor { call?: (...args: any[]) => void; diff --git a/types/tapable/tapable-tests.ts b/types/tapable/tapable-tests.ts index c78196c194..b1cbcf1e21 100644 --- a/types/tapable/tapable-tests.ts +++ b/types/tapable/tapable-tests.ts @@ -1,4 +1,16 @@ -import {Tapable, MultiHook, SyncHook} from "tapable"; +import { + Tapable, + MultiHook, + SyncHook, + SyncBailHook, + SyncWaterfallHook, + SyncLoopHook, + AsyncParallelHook, + AsyncParallelBailHook, + AsyncSeriesHook, + AsyncSeriesBailHook, + AsyncSeriesWaterfallHook +} from "tapable"; class DllPlugin { apply(compiler: Compiler) { @@ -45,3 +57,121 @@ compiler.applyPluginsParallelBailResult('doSomething', 'a', 'b'); compiler.applyPluginsParallelBailResult1('doSomething', 'a', callback); const multi = new MultiHook([new SyncHook(['hi'])]); + +const isNumber = (val: number) => val; +const isAny = (val: {a: { n: {y: '!'}}}) => val; +const isUndefined = (val: undefined) => val; + +// Without generics +(() => { + const hooks = { + syncHook: new SyncHook(['arg1']), + syncBailHook: new SyncBailHook(['arg1']), + syncWaterfallHook: new SyncWaterfallHook(['arg1']), + syncLoopHook: new SyncLoopHook(['arg1']), + asyncParallelHook: new AsyncParallelHook(['arg1']), + asyncParallelBailHook: new AsyncParallelBailHook(['arg1']), + asyncSeriesHook: new AsyncSeriesHook(['arg1']), + asyncSeriesBailHook: new AsyncSeriesBailHook(['arg1']), + asyncSeriesWaterfallHook: new AsyncSeriesWaterfallHook(['arg1']), + } + + // Without generics we won't get any information + // for the tap interface: + hooks.syncHook.tap('AHook', () => ('ReturnValue')); + hooks.syncBailHook.tap('AHook', () => ('ReturnValue')); + hooks.syncWaterfallHook.tap('AHook', () => ('ReturnValue')); + hooks.asyncParallelHook.tapPromise('AHook', async () => ('ReturnValue')); + hooks.asyncParallelBailHook.tapPromise('AHook', async () => ('ReturnValue')); + hooks.asyncSeriesHook.tapPromise('AHook', async () => ('ReturnValue')); + hooks.asyncSeriesBailHook.tapPromise('AHook', async () => ('ReturnValue')); + hooks.asyncSeriesWaterfallHook.tapPromise('AHook', async () => ('ReturnValue')); + + async function getHookResults() { + return { + syncHook: hooks.syncHook.call({ name: 'sue', age: 34 }), + syncBailHook: hooks.syncBailHook.call({ name: 'sue', age: 34 }), + syncWaterfallHook: hooks.syncWaterfallHook.call({ name: 'sue', age: 34 }), + syncLoopHook: hooks.syncLoopHook.call({ name: 'sue', age: 34 }), + asyncParallelHook: await hooks.asyncParallelHook.promise({ name: 'sue', age: 34 }), + asyncParallelBailHook: await hooks.asyncParallelBailHook.promise({ name: 'sue', age: 34 }), + asyncSeriesHook: await hooks.asyncSeriesHook.promise({ name: 'sue', age: 34 }), + asyncSeriesBailHook: await hooks.asyncSeriesBailHook.promise({ name: 'sue', age: 34 }), + asyncSeriesWaterfallHook: await hooks.asyncSeriesWaterfallHook.promise({ name: 'sue', age: 34 }), + } + } + + getHookResults().then((result) => { + // Allways undefined: + console.log(isUndefined(result.syncHook)); + console.log(isUndefined(result.asyncSeriesHook)); + console.log(isUndefined(result.asyncParallelHook)); + // Possible undefined: + console.log(isAny(result.syncBailHook!)); + console.log(isAny(result.asyncParallelHook!)); + console.log(isAny(result.syncBailHook!)); + console.log(isAny(result.asyncParallelHook!)); + console.log(isAny(result.asyncSeriesHook!)); + console.log(isAny(result.asyncSeriesBailHook!)); + // Allways defined: + console.log(isNumber(result.syncWaterfallHook.age)); + console.log(isNumber(result.asyncSeriesWaterfallHook.age)); + }); +})(); + +// With generics +(() => { + type Person = {name: string, age: number}; + const hooks = { + syncHook: new SyncHook(['arg1']), + syncBailHook: new SyncBailHook(['arg1']), + syncWaterfallHook: new SyncWaterfallHook(['arg1']), + syncLoopHook: new SyncLoopHook(['arg1']), + asyncParallelHook: new AsyncParallelHook(['arg1']), + asyncParallelBailHook: new AsyncParallelBailHook(['arg1']), + asyncSeriesHook: new AsyncSeriesHook(['arg1']), + asyncSeriesBailHook: new AsyncSeriesBailHook(['arg1']), + asyncSeriesWaterfallHook: new AsyncSeriesWaterfallHook(['arg1']), + } + + // Without generics we will get information + hooks.syncHook.tap('AHook', () => ('Any Return Value')); + hooks.syncBailHook.tap('AHook', (person) => person.age); + hooks.syncWaterfallHook.tap('AHook', (person) => ({ name: 'sue', age: person.age + 1 })); + hooks.asyncParallelHook.tapPromise('AHook', async () => ('ReturnValue')); + hooks.asyncParallelBailHook.tapPromise('AHook', async (person) => person.age); + hooks.asyncSeriesHook.tapPromise('AHook', async () => ('ReturnValue')); + hooks.asyncSeriesBailHook.tapPromise('AHook', async (person) => person.age); + hooks.asyncSeriesWaterfallHook.tapPromise('AHook', async (person) => ({ name: 'sue', age: person.age + 1 })); + + async function getHookResults() { + return { + syncHook: hooks.syncHook.call({ name: 'sue', age: 34 }), + syncBailHook: hooks.syncBailHook.call({ name: 'sue', age: 34 }), + syncWaterfallHook: hooks.syncWaterfallHook.call({ name: 'sue', age: 34 }), + syncLoopHook: hooks.syncLoopHook.call({ name: 'sue', age: 34 }), + asyncParallelHook: await hooks.asyncParallelHook.promise({ name: 'sue', age: 34 }), + asyncParallelBailHook: await hooks.asyncParallelBailHook.promise({ name: 'sue', age: 34 }), + asyncSeriesHook: await hooks.asyncSeriesHook.promise({ name: 'sue', age: 34 }), + asyncSeriesBailHook: await hooks.asyncSeriesBailHook.promise({ name: 'sue', age: 34 }), + asyncSeriesWaterfallHook: await hooks.asyncSeriesWaterfallHook.promise({ name: 'sue', age: 34 }), + } + } + + getHookResults().then((result) => { + // Allways undefined: + console.log(isUndefined(result.syncHook)); + console.log(isUndefined(result.asyncSeriesHook)); + console.log(isUndefined(result.asyncParallelHook)); + // Possible undefined: + console.log(isNumber(result.syncBailHook!)); + console.log(isNumber(result.asyncParallelHook!)); + console.log(isNumber(result.syncBailHook!)); + console.log(isNumber(result.asyncParallelHook!)); + console.log(isNumber(result.asyncSeriesHook!)); + console.log(isNumber(result.asyncSeriesBailHook!)); + // Allways defined: + console.log(isNumber(result.syncWaterfallHook.age)); + console.log(isNumber(result.asyncSeriesWaterfallHook.age)); + }); +})();