Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript child class function overloading

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?

like image 352
Daniel Avatar asked Jun 25 '16 05:06

Daniel


People also ask

Is function overloading possible in TypeScript?

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.

Can a class overload properties in TypeScript?

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.

How do I override a TypeScript function?

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.

Does TypeScript support multiple inheritance?

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.


2 Answers

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.

like image 55
zlumer Avatar answered Sep 24 '22 12:09

zlumer


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

like image 31
Ninh Pham Avatar answered Sep 26 '22 12:09

Ninh Pham