Search code examples
typescriptmultiple-inheritance

Typescript multiple class inheritance design


I am designing a Menu system for a restaurent in Typescript. I have defined an interface to implement necessary function for each Menu Item :

interface HasPrice {
    getPrice(): number;
}

Each menu item is defined by a class.

class Gobi implements HasPrice {
    getPrice() : number {
        return 50;
    }
}

class FriedRice implements HasPrice {
    getPrice() : number {
        return 100;
    }
}

I am using decorator class to add toppings. eg.Fried Rice with chicken

class FriedRiceWithChicken implements HasPrice {
    getPrice() : number {
        return super.getPrice() + 25;
    }
}

Now I want to extend this system for combo menus. eg. Fried Rice + Gobi

class FriedRiceAndGobi extends FriedRice, Gobi {
    getPrice() : number {
        return FriedRice.getPrice() + Gobi.getPrice();
    }
}

How can I implement combo classes? Is there a way I can write a generic class/method to implement combo menu?


Solution

  • Typescript does not have support for multiple inheritance.

    There's a couple of different reasons why you would want multiple inheritance. Your example is however not one of them.

    If, using your example, I would need a single class that encapsulates both ingredients, this is how I would approach this:

    class CombinedItem {
       private menuItems: HasPrice[];
       constructor(menuItems: hasPrice[]) {
          this.menuItems = menuItems;
       }
       getPrice() {
          return this.menuItems.reduce(
             (acc, curr) => acc + curr.getPrice(),
             0
          );
        }
    }
    

    This could then be constructed as such:

    const item = new CombinedItem([
       new Rice(),
       new Chicken()
    ]);
    

    CombinedItem is a class that can take any combination of inputs. If you want something really specific, you can do:

    class ChickenAndRice {
       private chicken: Chicken;
       private rice: Rice;
       constructor(chicken: Chicken, rice: Rice) {
          this.chicken = chicken;
          this.rice = rice;
       }
       getPrice() {
          return this.chicken.getPrice() + this.rice.getPrice();
        }
    }
    

    But I'm not sure why you would ever want this.

    Thinking in the direction of inheritance for your problem is a common mistake, and right solution is to compose objects and classes together instead of inherit behavior.