[TIL] <2020.05.28 ~ 06.01> Extending Classes and Interfaces / 클래스, 인터페이스 확장에 관하여

이성진·2020년 6월 2일
0

TIL

목록 보기
9/9

이 글은 !(Typescript Class: Extending-classes-and-interfaces-using-typescript)[https://www.pluralsight.com/blog/software-development/extending-classes-and-interfaces-using-typescript]를 번역한 글이고 오역, 의역 많습니다.. 글을 다 읽지 마시고 코드 보면서 이렇게 변하는 구나~ 하면서 이해해주세요.

인터페이스 그리고 클래스를 확장해봅시다.
다음 블로그 > declare typescript
다다음 블로그 > https://www.youtube.com/watch?v=Fgcu_iB2X04

class Auto {
    private _basePrice: number;
    engine: IEngine;
    state: string;
    make: string;
    model: string;
    year: number;
    accessoryList: string;
  
    constructor(options: IAutoOptions) {
        this.engine = options.engine;
        this.basePrice = options.basePrice;
        this.state = options.state;
        this.make = options.make;
        this.model = options.model;
        this.year = options.year;
    }
  
    calculateTotal() : number {
        var taxRate = TaxRateInfo.getTaxRate(this.state);
        return this.basePrice + (taxRate.rate * this.basePrice);
    }
  
    addAccessories(...accessories: Accessory[]) {
        this.accessoryList = '';
        for (var i = 0; i < accessories.length; i++) {
            var ac = accessories[i];
            this.accessoryList += ac.accessoryNumber + ' ' + 					ac.title + '<br />';
        }
    }
  
    getAccessoryList(): string {
        return this.accessoryList;
    }
  
  	get basePrice(): number {
        return this._basePrice;
    }
  
    set basePrice(value: number) {
        if (value <= 0) throw 'price must be >= 0';
        this._basePrice = value;
    }
}

코드를 보시면 다양한 필드, 생성자, 함수(스프레드 매개변수같은 스페셜 타입을 포함한 함수) 그리고 basePrice로 이름지어진 프로퍼티 get, set 을 볼 수 있습니다.

비록 상속과는 관계가 없지만, --target 스위치를 사용하여 TypeScript 컴파일 대상을 ECMAScript 5로 설정할 때만 TypeScript의 속성이 작동한다는 점에 유의해야 합니다. (예: tsc.ext --target ES5 YourFile.ts)

interface IEngine {
    start(callback: (startStatus: bool, engineType: string) => void) : void;
    stop(callback: (stopStatus: bool, engineType: string) => void) : void;
}

interface IAutoOptions {
    engine: IEngine;
    basePrice: number;
    state: string;
    make: string;
    model: string;
    year: number;
}

IEngine 인터페이스는 start() 그리고 stop() 메소드를 둘 다 콜백함수로 허용합니다.
콜백 함수는 타입이 boolean, string 인 두 개의 매개 변수를 필수로 받아야 합니다.
implement를 사용한 인터페이스 예제를 보여드리겠습니다.
인터페이스를 implement 받는 클래스는 인터페이스의 ? 연산자로 정의되지 않은 모든 멤버를 반드시 정의해야 합니다.

class Engine implements IEngine {
  constructor(public horsePower: number, public enginType: string) { }
  start(callback: (startStatus: bool, engineType: string) => void): vod {
    window.setTimeout(() => {
      callback(true, this.engineType);
    }, 1000);
  }
  
  stop(callback: (stopStatus: bool, engineType: string) => void): vod {
    window.setTimeout(() => {
      callback(true, this.engineType);
    }, 1000);
  }
}

Auto 클래스를 확장한 Truck 클래스가 있다고 했을 때 우리는 Auto 에 있는 코드들을 복사/붙여넣기 하기 싫습니다. 운 좋게도, 타입스크립트는 우리에게 상속 기능을 제공해줍니다. 아래의 코드가 Auto 클래스를 상속 받은 Truck 클래스 입니다.

class Truck extends Auto {
  private _bedLength: string;
  fourByFour: bool;
  
  constructor(options: ITruckOptions) {
    super(options);
    this.bedLength = options.bedLength; // Auto 클래스의 멤버
    this.fourByFour = options.fourByFour; // Auto 클래스의 맴버
  }
  
  get bedLength(): string {
    return this._bedLength;
  }
  set bedLength(value: string) {
    if (value == null || value == undefined || value == "") {
      this._bedLength = "Short";
    } else {
      this._bedLength = value;
    }
  }
}

Truck 클래스는 bedLength 그리고 foutByFour 정의하면서 Auto 클래스를 확장하였습니다.

마찬가지로 Interfaceextends 키워드를 사용함으로서 확장할 수 있습니다.

interface ITruckOptions extends IAutoOptions {
  bedLength: string;
  foutByFour: bool;
}

트럭 클래스는 bedLength 그리고 fourByFour 기능을 추가함으로서 오토 클래스를 확장했습니다.
인터페이스 또한 extends 키워드를 사용해서 상속을 받을 수 있습니다.

interface ITruckOptions extends IAutoOptions {
  bedLength: string;
  fourByFour: bool;
}

ITruckOptions 인터페이스에 맞게 오브젝트를 트럭 클래스 생성자의 매개변수로 주는 트럭 인스턴스 객체를 생성하는 예제입니다.

let truck = new Truck({
  engine: new Engine(250, "V8"),
  basePrice: 45000,
  state: "Arizona",
  make: "Ford",
  model: "F-150",
  year: 2013,
  bedLength: "Short Bed",
  fourByFour: true
});

Javascript의 상속

타입스크립트의 extends 키워드가 간단하고 편리한 함수형 상속을 지원한다는 것을 볼 수 있습니다. 그러나 Javascript 가 컴파일 할 때 뒤에서 무슨 일이 일어날까요?
어쨋든, Javascript는 ECMAScript 5 또는 그 이전 버전에서는 extends 또는 inherits 키워드를 가지고 있지 않습니다.
만약 Typescript가 Javascript로 컴파일 한 코드를 본다면 Javascript 프로토타입을 사용한 상속한 척 하는 작은 마법을 보실 것입니다.

첫 번째로, 생성된 자바스크립트에 __extends 라는 변수가 추가됩니다. 그리고 아래와 같은 두 개의 매개변수를 가지는 함수가 할당됩니다.

var __extends = this.__extends || function (d, b) {
  function __() { this.constructor = d; }
  __.prototype = b.prototype;
  d.prototype = new __();
};

이 함수는 파생(derived)/자식 타입(d 파라미터)과 기본 타입(b 파라미터) 받습니다. 함수 안의 이름이 __ 인 오브젝트가 만들어졌습니다. 그리고 생성자에서 __ 에 파생(derived)타입을 할당합니다. 거기서, 기본 타입의 프로토타입에 오브젝트의 프로토타입을 할당합니다. 작업을 끝내려면 __ 인스턴스 객체를 만들고 자식 타입의 프로토타입으로 할당됩니다. 그래서 새 인스턴스가 기본 타입의 멤버를 가져갑니다.
끝으로, 자바스크립트는 두 오브젝트 사이를 상속할 수 있도록 하는 재사용 함수를 생성합니다.

만약 프로토타입에 처음이시라면 아마도 타입스크립트 extends 키워드의 간단함의 진가를 알아보셨을 것입니다.

__extends 함수는 Javascript로 변환된 코드에서 Truck과 Auto 사이의 상속을 다루는 데에도 사용되었습니다.
다음 예제는 변환된 대표적인 Truck 클래스를 보여줍니다.

var Truck = (function (_super) {
  __extends(Truck, _super);
  function Truck(options) {
    _super.call(this, options);
    this.bedLength = options.bedLength;
    this.fourByFour = options.fourByFour;
  }
  Object.defineProperty(Truck.prototype, "bedLength", {
    get: function () {
      return this._bedLength;
    },
    set: function (value) {
      if (value == null || value == undefined || value == "") {
        this._bedLength = "Short";
      } else {
        this._bedLength = value;
      }
    },
    enumerable: true,
    configurable: true
  });
  return Truck;
})(Auto);

Truck은 이름이 _super인 매개변수를 받는 함수를 할당받습니다. 이 매개변수는 상속하고 싶은 부모 클래스를 대표합니다. Truck에 할당된 함수는 코드 하단에 자체 설치되며, _super 파라미터의 값에 대해 (예제의 Auto) 파생되는 기본 클래스가 전달된다. __extends 함수는 Truck 안의 호출에 의해 앞에서 논의되었다. 그리고 파생된 타입(Truck), 기본 타입(Auto)들은 파라미터로서 전달된다. 그러면 앞서 논의한 대로 prototypes을 사용하여 상속의 마법이 일어난다.

결론

// 이 부분은 제 입맛대로 쓴 거에요..!

위의 예제를 통해 우리는 Typescript의 extedns는 컴파일러를 이용해 내부적으로 Javascript로 변환되면서 모든 브라우저에서 사용할 수 있게 하는 것을 알았다.
interface, implement 그리고 extend가 타입스크립트에서 어떻게 만들어지는 지를 알았다.

profile
개발보다 회사 매출에 영향력을 주는 개발자

0개의 댓글