Reputation: 1060
I'm trying to create a class which allows passing a callback to alter the side-effects of a method. If you don't pass a callback, then the method will be called directly. This is a basic example:
class Button<T = void> {
private clickWrapper?: (click: Function) => T
private _click() {
// do the click here
return null;
}
constructor(clickWrapper?: (click: Function) => T) {
this.clickWrapper = clickWrapper;
}
public click() {
if (this.clickWrapper) {
return this.clickWrapper(this._click.bind(this));
} else {
return this._click();
}
}
}
class Foo {
public doStuff() {
console.log('hello');
}
}
const button = new Button<Foo>(click => {
// do some stuff
click();
return new Foo();
});
const foo = button.click();
foo.doStuff();
const button2 = new Button();
button2.click();
This works, but foo.doStuff()
complains that foo may be null - even though in this case I provided a clickWrapper, so the return value of button.click()
cannot be null, it must be an instance of Foo. Is there a better way to define this?
The second issue is I have to copy the Button constructor's parameter type when I've already declared it for Button.clickWrapper. How do I avoid having to declare the type on the private property and constructor parameter?
Upvotes: 0
Views: 744
Reputation: 416
I have updated you code snippet:
class Button<T = null> {
constructor(private clickWrapper?: (click: Function) => T) {}
private _click() {
// do the click here
return null;
}
public click(): T {
if (this.clickWrapper) {
return this.clickWrapper(this._click.bind(this));
} else {
return this._click();
}
}
}
class Foo {
public doStuff() {
console.log("hello");
}
}
const button = new Button<Foo>(click => {
// do some stuff
click();
return new Foo();
});
const foo = button.click();
foo.doStuff();
const button2 = new Button();
button2.click();
Two things:
public click
function so it assumes T | null
, since default _click
function returns null
constructor assignment
(just add private
or public
keyword to constructor param)Upvotes: 1
Reputation: 401
interface Callback<V> {
(arg: () => void): V
}
class Button<T = void> {
constructor(private callback?: Callback<T>) {}
private onClick = () => {
}
public click = () => {
if (this.callback) {
return this.callback(this.onClick)
} else {
return this.onClick()
}
}
}
const button = new Button<number>(
click => {
click()
return 2 +2
}
)
console.log(button.click()) // 4
I update your code to solve your problems
private callback?
to the constructor to inject the argument to the class void function
, you are returning null, so that didn't match with your clickWrapper
type, I assume you aren't gonna return anything from the click
function so I update that type to match too with a void function
Upvotes: 0