I've been trying to find a way to accomplish this using only one classes, but i'm not sure it's possible. It makes sense, since having the same function called in a different way is not very clean.
What you could do, is use an interface, a parent class and multiple child class. This would allow you to use one or the other, and stay DRY at the same time. Here is my take on this problem.
// we create an interface with an optional parameter "a"
interface ITest {
run(a?: number) : void;
}
// we create a super class that will handle the process of the "run" function.
// this class has a function with a necessary parameter
abstract class AbstractTest<T extends string|number> {
run(a: T) {
console.log('ran with param: ', a);
}
}
// We create two sub class, one for the run with no parameter, one with the run with one parameter.
// Both classes implements the interface and calls the parent function "run".
// this class does not extends the "run" function, since it is the same as the parent one
class TestNumber<T extends number> extends AbstractTest<T> implements ITest {}
// this class extends the "run" function, since it needs to process the fact that there is no parameters passsed
// to the "run" function. I've used a default value here, but it will depend on your use case.
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)
}
}
// we create new objects based on the need.
const a = new TestNumber<number>();
const b = new TestString<string>();
// this function call works since we've passed a parameter
a.run(42);
// this one does not work and an error is thrown.
a.run()
// this function call works great without an argument.
b.run()
I've placed comments to explain the changes. here is a typescript playground with the working code