I am trying to create a function that accepts extensions as arguments, and returns an object that is typed as the combination of all the extensions.
To better illustrate, here is a basic example:
const withNotification = () => ({ notify: (message: string): void => void 0 });
const withDialog = () => ({ dialog: (data: any): void => void 0 });
const compose = (...extensions: any[]): any => null!;
const composed = compose(withNotification(), withDialog());
// When writing the following, the signature should be recognized
composed.notify('OK'); // Works
composed.notify(0); // Does not work (not a string)
composed.dialog({}); // Works
composed.dialog(); // Does not work (no parameter)
My approach so far is the following:
type Extension<T extends object> = { [key in keyof T]: T[key] };
const withNotification = () => ({ notify: (message: string): void => void 0 });
const withDialog = () => ({ dialog: (data: any): void => void 0 });
const compose = <T extends object>(...extensions: Extension<T>[]): T => null!;
const composed = compose(withNotification(), withDialog());
composed.notify('OK');
composed.notify(0);
composed.dialog({});
composed.dialog();
What happens is that calling notify
is recognized, whereas dialog
is not. I understand that this is because my T
generic that is not “spreading” to all extensions, but I don’t know how to achieve that.
StackBlitz
2