How can I achieve something similar to this pattern in typescript?
class A {
Init(param1: number) {
// some code
}
}
class B extends A {
Init(param1: number, param2: string) {
// some more code
}
}
The code snipped above appears like it should work, however on close inspection of How Typescript function overloading works it makes sense that an error is thrown:
TS2415: 'Class 'B' incorrectly extends base class 'A'.
Types of property 'Init' are incompatible.
I know that constructor functions allow this behaviour, but I can't use constructors here as these objects are pooled for memory efficiency.
I could provide another definition of Init() in class A:
class A {
Init(param1: number, param2: string): void;
Init(param1: number) {
// some code
}
}
However this is less than ideal as now the base class needs to know about all of its derived classes.
A third option would be to rename the Init method in class B but that would not only be pretty ugly and confusing, but leave exposed the Init() method in the base class, which would cause difficult-to-detect bugs when the base class Init() is called by mistake.
Is there any way to implement this pattern that doesn't have the pitfalls of the aforementioned approaches?
TypeScript provides the concept of function overloading. You can have multiple functions with the same name but different parameter types and return type. However, the number of parameters should be the same.
Method overloading is a familiar concept from traditional programming languages like Java or C#. It allows a class to have multiple methods with the same name if their signature is different. But Typescript only helps us during edit and compile time and not at runtime.
To override a class method in TypeScript, extend from the parent class and define a method with the same name. Note that the types of the parameters and the return type of the method have to be compatible with the parent's implementation. Copied! class Parent { doMath(a: number, b: number): number { console.
An inherited derived class acquires the properties and behaviors of the base class. TypeScript supports single inheritance and multilevel inheritance. We can not implement hybrid and multiple inheritances using TypeScript.
TypeScript complains about methods not being interchangeable: what would happen if you do the following?
let a:A = new A(); // a is of type A
a.Init(1)
a = new B(); // a is still of type A, even if it contains B inside
a.Init(1) // second parameter is missing for B, but totally valid for A, will it explode?
If you don't need them to be interchangeable, modify B
's signature to comply with A
's:
class B extends A {
Init(param1: number, param2?: string) { // param 2 is optional
// some more code
}
}
However, you might find yourself in a situation where you need to create a class with totally different method signature:
class C extends A {
Init(param1: string) { // param 1 is now string instead of number
// some more code
}
}
In this case, add a list of method signatures that satisfy both current class and base class calls.
class C extends A {
Init(param1: number)
Init(param1: string)
Init(param1: number | string) { // param 1 is now of type number | string (you can also use <any>)
if (typeof param1 === "string") { // param 1 is now guaranteed to be string
// some more code
}
}
}
That way the A
class doesn't have to know about any of the derived classes. As a trade-off, you need to specify a list of signatures that satisfies both base class and sub class method calls.
For someone who wants to extend a type. Basing on zlumer's answer, and using Intersection types
interface ConsumerGroup {
on(message: 'message'): void
on(message: 'error'): void
}
interface ConsumerGroup2 {
on(message: 'messageDecoded'): void;
on(message: 'rawMessage'): void;
}
// Intersection types
type ConsumerGroupEx = ConsumerGroup2 & ConsumerGroup;
function newEvent(): ConsumerGroupEx {
return "just for test" as unknown as ConsumerGroupEx;
}
const evt = newEvent();
evt.on('messageDecoded'); // ok
evt.on('message'); // ok
evt.on('error'); // ok
evt.on('notExist'); // compilation error
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