Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript Examples #33

Open
abarke opened this issue Dec 1, 2021 · 7 comments
Open

TypeScript Examples #33

abarke opened this issue Dec 1, 2021 · 7 comments

Comments

@abarke
Copy link
Contributor

abarke commented Dec 1, 2021

Would be nice to have examples in the README for using types with Hookable e.g.

import { createHooks } from 'hookable';

export type HookTypes = {
  hello: (value: string) => void;
  ping: (value: string) => string;
};

// Create a hookable instance
const hooks = createHooks<HookTypes>();

// Hook on 'hello'
hooks.hook('hello', (val: string) => console.log(val));

// Call 'hello' hook and pass 'Hello World!'
hooks.callHook('hello', 'Hello World!');

// Hook on 'ping' that returns 'PONG'
hooks.hook('ping', (val: string) => {
  console.log(val);
  return 'PONG';
});

// Call 'ping' hook and pass 'PING'
hooks.callHook('ping', 'PING').then((val) => {
  console.log(val);
});

However I ran into an unexpected issue with the return type... if I set the type to the following it works without errors. But surely I need to specify the return type here right?

ping: (value: string) => void

Argument of type '(val: string) => string' is not assignable to parameter of type 'never'.(2345)

Editor: https://stackblitz.com/edit/typescript-fkfd5n?devtoolsheight=33&file=index.ts

@abarke
Copy link
Contributor Author

abarke commented Dec 1, 2021

Just realized that HookCallback expects a function that returns Promise<void> | void,
however in the linked example that it seems you can return a value when callHook resolves.

export type HookCallback = (...args: any) => Promise<void> | void

https://github.com/unjs/hookable/blob/main/src/types.ts#L1

Is that expected?

@abarke
Copy link
Contributor Author

abarke commented Dec 7, 2021

@pi0 any feedback would be most appreciated 🙂

@abarke
Copy link
Contributor Author

abarke commented Dec 7, 2021

Also I have noticed that although my JetBrains IDE seems to think that callHook always returns a Promise, this is simply not the case.

I get this message:
image

However one would simply go ahead and put a then() on the end and do something like call a logging method. e.g.

hooks
        .callHook(Hook.BEFORE_SERIALIZED, msg)
        .then(() => console.log("test"))

This only works if two conditions are met...

  1. There is a registered hook
  2. When adding a hook the callBack function is a Promise e.g...
hooks.hook(Hook.BEFORE_SERIALIZED, async (msg) => {
  console.log("✅", msg.Message)
})

If any of these conditions are not met then a runtime error occurs (there is no then() on undefined).

The type definition

callHook<NameT extends HookNameT>(name: NameT, ...args: Parameters<InferCallback<HooksT, NameT>>): Promise<any>;

should perhaps be

callHook<NameT extends HookNameT>(name: NameT, ...args: Parameters<InferCallback<HooksT, NameT>>): void | Promise<any>;

I edited the type def in Hookable directly in my IDE and the ignored promise warning is gone 🎉

We are building a library that exports the hooks in the config so it's quite normal to have unregistered hooks (noop).

Regarding points 1... The core lib where callHook() is used cannot be expected to return a Promise, therefore cannot be used with .then() or await. Reason: If no hooks are registered then one can not expect a Promise. However this should potentially be the default behavior when callHook() is called without a registered hook. Simply return a Promise.resolve() by default should this be expected.

Regarding point 2... The hook() method may be used in another plugin somewhere and should it not use a async method callback then it would break the whole app as I would call .then() on undefined.

@pi0
Copy link
Member

pi0 commented Aug 23, 2022

@danielroe Can you please help on this issue? 🙏🏼

@kaikaibenkai
Copy link

Could anyone answer this
In some cases, certain operations require consultation with hooks beforehand.

For example:

const msg = await app.callHook('user:login:before');
if (msg === undefined) {
  Message.success('Hi, you are logged in!');
} else {
  Message.error('Oops!' + msg);
  return;
}
// ...

@danielroe 🙏🙏

@MichaelGitArt
Copy link

It would be really helpful to see typescript examples 👀

@affinage-digital
Copy link

Some of working sample:

import { Hookable } from 'hookable';

export class Parser extends Hookable<{
    /** super tsdoc comment working too */
    someOneHook: (rows: string[]) => void;
}> {
    rows: string[] = [];

    constructor() {
        super(); // init instance of Hookable
    }

    getRows() {
        this.rows = ['a', 'b', 'c'];
        this.callHook('someOneHook', this.rows);
    }
}
import { Parser } from '...';

const parser = new Parser();

// subscribe
const unregisterSomeOneHook = parser.hook('someOneHook', rows => console.log(rows));

parser.getRows();

// unsubscribe
unregisterSomeOneHook();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants