Multiple Inheritance

And

TypeScript Interfaces

Multiple Inerhitance

Just like it sounds..one object's prototype inheriting from multiple other objects prototoypes.

JavaScript doesn't natively support multiple inheritance, but we can use a design pattern called a mixin.

A mixin you say?

mixin is a design pattern where you iterate over multiple objects properties to combine them into a single new object. 

function extend(destination, source) {
  for (var k in source) {
    if (source.hasOwnProperty(k)) {
      destination[k] = source[k];
    }
  }
  return destination; 
}

And now you have multiple inheritance.

This method allows us to inherit from (extend) as many other object's as we want.

function extend(destination, source) {
  for (var k in source) {
    if (source.hasOwnProperty(k)) {
      destination[k] = source[k];
    }
  }
  return destination; 
}
function Taco(){

}
Taco.prototype.eat = function(){
    /*do stuff*/ 
};

function Beans(){

}
Beans.prototype.cook = function(){
    /*do stuff*/ 
};

function Guacomole(){

}
Guacomole.prototype.spread = function(){
    /*do stuff*/ 
};

extend(Taco.prototype, Beans);

console.log(Taco); 

By using the extend function to implement the mixin pattern we created references to the super prototype methods.

Also notice that we don't inherit a constructor with the mixin

Since we're adding methods to the objects existing prototype, without Object.create() to assign a new prototype object, the constructor remains intact.

var canFly = function() {
  this.price = 9.99;
  this.takeOff = function() {
    //fly baby
  };
  return this;
};

var isSubmersible = function() {
  this.oxygenTanks = 4;
  this.dive = function() {
      //go deep
    };
  return this;
}

var Car = function(opts) {
  this.wheels = 4;
  if (opts.fly) {
    canFly.call(Car.prototype);
  }
  if (opts.swim) {
    isSubmersible.call(Car.prototype);
  }
};

var flyingSubmaringCar = new Car({ fly : true, swim : true });
console.log(flyingSubmaringCar);

"A mixin should be a process not an object"

Although this achieves multiple inheritance best practice says:

"Something that adds behavior"

Interfaces (TypeScript)

Mixins allowed us to inherit behavior from multiple objects...

...Interfaces allow us to define a contract.

If any object implements an interface it must provide certain behavior and properties

If you wanna be in the band, you gotta wear the makeup bro...

Easiest Way To Remember  Interfaces 

//we could define an interface for a Car class such that 
//every car must have an engine and a color like this:

interface ICar{
    engine: string;
    color: string;
}



//The Car class adheres to the interface ICar because it implements ICar

class Car implements ICar {
    constructor (public engine: string, public color: string) {
    }
} 


//Create a new instance of a car and fulfills all requirements of the ICar interface 'contract'
var hondaAccord = new Car('V6', 'green');
alert(hondaAccord.engine);

Remember an interface is "just a contract".

By abiding by the contract your object will implement all the requirements of the contract

 

http://www.typescriptlang.org/Playground/

class Car {
    private _basePrice: number;
    engine: IEngine;

    constructor(options: IAutoOptions) {
        this._basePrice = options.basePrice;
        this.engine = options.engine;
    }
    
    drive() : number {
        console.log('driving');
		return 1000;
    }

    get price(): number {
        return this._basePrice;
    }

    set price(value: number) {
        this._basePrice = value;
    }
} 

Implementing interfaces on subclasses

interface IEngine {
    start() : void;
    stop() : void;
}

interface IAutoOptions {
    engine: IEngine;
    basePrice: number;
}

interface ICanFly {
  altitude: number;
  fly() : void;
}

class FlyingEngine implements IEngine { 
    start() : void { }
    stop() : void { }
}

class FlyingCar extends Car implements ICanFly {
	altitude: number;
	
  constructor(options: IAutoOptions){
    super(options);
    this.altitude = 0;
  };
  fly() : void {
    this.engine.start();
    console.log('flying');
  }

}

//Create a new flying car
var fc = new FlyingCar({basePrice: 1000, 
    engine: new FlyingEngine()})

alert(fc.price); //[Alert] 1000
class Bird implements ICanFly {
	name: string;
	altitude: number;
	
	constructor (name: string){
		this.name = name;
		this.altitude = 100;
	};
	fly() : void {
    console.log('flying');
  }
}

var fc = new FlyingCar({basePrice: 1000, engine: new FlyingEngine()})

var tweety = new Bird('Tweety');

var polly = new Bird('Polly');

var flyingThings: Array<ICanFly> = [fc, tweety, polly];

for (var i=0; i< flyingThings.length; i++) {
	alert(flyingThings[i].altitude);
} 

Verifying type with implementations

Resources

Made with Slides.com