Nishant Baranwal
Nishant Baranwal

Reputation: 1238

Typescript interface method Vs abstract method syntax difference

unable to understand why the syntax is different for method declaration in an interface and abstract method in an abstract class

 interface Moveable {
      start: () => void;
      stop: () => void; // why it is not declared as stop(): void;
  }

  abstract class Vehicle implements Moveable {
      start(): void {
          console.log('Vehicle is moving');
      }
      stop(): void {
          console.log('Vehicle stopped');
      }
      abstract getModal(): void; // why it can not be not defined as getModal: () => void; as it is done for interface
  }

  class Car extends Vehicle {
      getModal() {
          console.log('get modal');
      }
      private test(): void {
          console.log("The car is being tested...");
      }
  }

Upvotes: 3

Views: 405

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249676

There is a difference between the two syntaxes. start: () => void; declares a field that happens to be a function. start(): void; declares a method. When you use them there is no visible difference between the two, there are however differences between what can be done with them.

An interface field that is a function can be implemented by a class method, but you can use either declaration type in the interface, this would have achieved the same effect:

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

While you can declare an abstract field in the abstract class it has to also be implemented by a field it can't be implemented by a method:

class CarNok extends Vehicle {
    getModal() { } // Error, Class 'Vehicle' defines instance member property 'getModal', but extended class 'CarNok' defines it as instance member function
}

class CarOk extends Vehicle {
    getModal: () => { }
}

With regard to the difference between fields of type function and methods, you should keep in mind that methods end up on the prototype, while fields end up on the instance, so there is a performance penalty in terms of memory allocations (for simple scenarios it should not be a problem but if you create a lot of instances you might run into troubles). Also there are differences in terms of what happens with this:

class Car {
    test = 'Car'
    method(){ 
        console.log(this.test); // this is typed as Car but depends on the caller to be passed in corectly (see usage)
    }
    // Useful when we pass fieldWithArrow to event handlers and we want this to be bound to the instance
    fieldWithArrow = () => { 
        console.log(this.test); // this is typed as Car and will be bound to the current instance (thenically it is captured in the constructor when the value is assigned)
    }
    fieldWithFunction = function () { 
        console.log(this.test); // this is typed as any, since this function is just fucntion not a member of Car (might even give a compielr error depending on your settings)
    }
}

let cc = new Car();
cc.method(); // Will output 'Car'
cc.method.apply({ test: 'Not a car'}) // Will output 'Not a car' since we can pass in an arbitrary this to method
cc.fieldWithArrow() // Will output 'Car'
cc.fieldWithArrow.apply({test : 'Not a car'}) // Will output 'Car', this is bound to the function no matter what we pass to apply

cc.fieldWithFunction(); // Will output 'Car', the  function is not declared as a member but is called on the instance of Car
cc.fieldWithFunction.apply({ test: 'Not a car'}) // Will output 'Not a car' since we can pass in an arbitrary this to method

Upvotes: 4

Related Questions