I've been exploring different approaches to solve this using a single class, but I'm uncertain if it's achievable. It seems logical, as having the same function invoked in multiple ways can be quite confusing.
One potential solution is to utilize an interface, a parent class, and several child classes. This method would enable you to choose between them while remaining DRY at the same time. Here's my perspective on tackling this issue.
// define an interface with an optional parameter "a"
interface ITest {
run(a?: number): void;
}
// create a superclass to manage the "run" function process.
// this class includes a function with a required parameter
abstract class AbstractTest<T extends string|number> {
run(a: T) {
console.log('executed with param: ', a);
}
}
// Define two subclasses, one for running without a parameter and the other with a parameter.
// Both classes implement the interface and call the parent function "run".
// this class does not extend the "run" function since it mirrors the parent function
class TestNumber<T extends number> extends AbstractTest<T> implements ITest {}
// this class extends the "run" function as it needs to handle cases where no parameters are passed
// I've assigned a default value here, which can vary based on your requirements.
class TestString<T extends string> extends AbstractTest<T> implements ITest {
public static readonly DEFAULT_VALUE = 'some value';
run(): void {
super.run(TestString.DEFAULT_VALUE as T)
}
}
// instantiate new objects based on the need.
const a = new TestNumber<number>();
const b = new TestString<string>();
// calling this function works when passing a parameter
a.run(42);
// this call won't work and will throw an error
a.run()
// this function call works perfectly without an argument
b.run()
I've added comments to clarify the modifications made. here is a typescript playground showcasing the functioning code