diff --git a/README.md b/README.md index ebcf419..4f6118c 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,6 @@ ### Singular hook -Recommended for [TypeScript](#typescript) - ```js // instantiate singular hook API const hook = new Hook.Singular(); @@ -526,49 +524,116 @@ hookCollection.remove("save", validateRecord); ## TypeScript -This library contains type definitions for TypeScript. When you use TypeScript we highly recommend using the `Hook.Singular` constructor for your hooks as this allows you to pass along type information for the options object. For example: +This library contains type definitions for TypeScript. + +### Type support for `Singular`: ```ts +import { Hook } from 'before-after-hook'; -import {Hook} from 'before-after-hook' +type O = { foo: string }; // type for options +type R = { bar: number }; // type for result +type E = Error; // type for error -interface Foo { - bar: string - num: number; -} +const hook = new Hook.Singular(); -const hook = new Hook.Singular(); +hook.before((options) => { + // `options.foo` has `string` type -hook.before(function (foo) { + // not allowed + options.foo = 42; - // typescript will complain about the following mutation attempts - foo.hello = 'world' - foo.bar = 123 + // allowed + options.foo = 'Forty-Two'; +}); - // yet this is valid - foo.bar = 'other-string' - foo.num = 123 -}) +const hookedMethod = hook( + (options) => { + // `options.foo` has `string` type -const foo = hook(function(foo) { - // handle `foo` - foo.bar = 'another-string' -}, {bar: 'random-string'}) + // not allowed, because it does not satisfy the `R` type + return { foo: 42 }; -// foo outputs -{ - bar: 'another-string', - num: 123 -} + // allowed + return { bar: 42 }; + }, + { foo: 'Forty-Two' } +); +``` + +You can choose not to pass the types for options, result or error. So, these are completely valid: + +```ts +const hook = new Hook.Singular(); +const hook = new Hook.Singular(); +const hook = new Hook.Singular(); +``` + +In these cases, the omitted types will implicitly be `any`. + +### Type support for `Collection`: + +`Collection` also has strict type support. You can use it like this: + +```ts +import { Hook } from 'before-after-hook'; + +type HooksType = { + add: { O: { type: string }; R: { id: number }; E: Error }; + save: { O: { type: string }; R: { id: number } }; + read: { O: { id: number; foo: number } }; + destroy: { O: { id: number; foo: string } }; +}; + +const hooks = Hook.Collection(); + +hooks.before('destroy', (options) => { + // `options.id` has `number` type +}); + +hooks.error('add', (err, options) => { + // `options.type` has `string` type + // `err` is `instanceof Error` +}); + +hooks.error('save', (err, options) => { + // `options.type` has `string` type + // `err` has type `any` +}); + +hooks.after('save', (result, options) => { + // `options.type` has `string` type + // `result.id` has `number` type +}); + +hooks.before(['add', 'save'], (options) => { + // `options.type` has `string` type +}); + +hooks.error(['add', 'save'], (err, options) => { + // `options.type` has `string` type + // `err` has `any` type, because `E` was not defined for `save` +}); + +hooks.before(['read', 'destroy'], (options) => { + // `options.id` has `number` type + // `options.foo` has `number | string` type +}); +``` + +You can choose not to pass the types altogether. In that case, everything will implicitly be `any`: + +```ts +const hook = new Hook.Collection(); ``` -An alternative import: +Alternative imports: ```ts -import { Singular, Collection } from "before-after-hook"; +import { Singular, Collection } from 'before-after-hook'; -const hook = new Singular<{ foo: string }>(); -const hookCollection = new Collection(); +const hook = new Singular(); +const hooks = new Collection(); ``` ## Upgrading to 1.4