I am in the process of writing a new TypeScript class which takes a generic value that will be used as the input to a function. If a value isn't given, than the function should not take any inputs.
Ideally the class would be overloaded like this.
class Emitter<T = void> {
public activate(): void // When T is void
public activate(arg: T): void // When T isn't void
public activate(arg?: T) { /* ... */ }
}
Having the method be a function property works in theory but requires a @ts-ignore
on the method's implementation.
type OneArgFn<T> = T extends void
? () => void
: (arg: T) => void
interface Emitter<T> {
readonly activate: OneArgFn<T>
}
Another possibility is to export a different constructor when a Generic is provided or not, such as the following
interface EmitterNoArg extends Emitter {
activate: () => true
}
interface EmitterOneArg<T> extends Emitter<T> {
activate: (arg: T) => void
}
interface EmitterConstructor {
new(): Emitter
new(): EmitterNoArg
new<T>(): EmitterOneArg<T>
}
but then to export it the unknown
keyword is required.
export default Emitter as unknown as EmitterConstructor
These, do not seem to be optimal. Is there a proper way to have conditional arguments based on the Generic's type? I would think TypeScript's new conditional types would solve this issue.
One way to do it would be using tuples in rest parameters in a separate public signature:
type OneArgFn<T> = T extends void
? () => void
: (arg: T) => void
class Emitter<T = void> {
public activate(...a: Parameters<OneArgFn<T>>): void
public activate(arg?: T) { /* ... */ }
}
new Emitter().activate();
new Emitter<string>().activate("") // in 3.4 argument names are preserved
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With