TypeScript

typescript에서의 class

citron031 2023. 6. 6. 11:27

타입스크립트는 클래스 문법에 대한 추가적인 지원이 있다.

따라서, 클래스를 작성할 때 타입스크립트는 자바스크립트와는 다른 문법을 사용하므로 이에 대해서 글을 남기도록 하였다.

 

interface & type

interface Bus {
  custommer: string[];
  driver: string;
  callBus: () => string;
  getCustomer: () => string[];
  onBoardBus: (custommer: string) => void;
}

위와 같은 interface는 타입스크립트에서 객체의 타입을 표현하기 위해서 사용할 수 있다.

다만, java와 같은 객체지향 언어와 마찬가지로 interface를 implements하여 말 그대로 클래스의 인터페이스로 사용할 수 있다.

class MyBus implements Bus {
  custommer: string[] = [];
  driver = "me";

  constructor(name: string) {
    this.driver = name;
  }

  callBus = () => {
    console.log(this.driver);
    return this.driver
  };
  getCustomer = () => this.custommer;
  onBoardBus = (custommer: string) => {
    this.custommer.push(custommer);
  }
}

만약, 인터페이스에 명시되었지만 이를 이식한 클래스에서 실제 구현이 되지 않은 변수나 함수가 있다면 타입스크립트 오류가 발생한다.

const myBus = new MyBus("Driver");
myBus.callBus();
console.log(myBus.driver);

console.log(myBus.getCustomer());
myBus.onBoardBus("Park");
myBus.onBoardBus("Lee");
myBus.onBoardBus("One");
myBus.onBoardBus("Bob");
myBus.onBoardBus("Test");
myBus.onBoardBus("Kim");
console.log(myBus.getCustomer());

구현한 클래스가 잘 작동함을 확인할 수 있다.

 

또한, type 키워드역시 implements 될 수 있다.

type Cup = {
  id: number;
  clean: () => void;
};

class Bottle implements Cup {
  id: number = 12;
  clean = () => console.log("clean");
}

 

abstract

타입스크립트에서는 자바스크립트와 달리 추상 클래스를 생성하여 사용할 수 있다.

추상클래스는 내부에 구현이 직접 될 수도 있고, abstract로 구현을 생략하고 상속받을 클래스에서 실제 구현을 할 수도 있다.

abstract class BusTime {
  abstract arrivalTime: () => number;
  consoleHello() {
    console.log("hello");
  }
}

class Bus extends BusTime {
  arrivalTime: () => number = () => {
    return new Date().getMinutes();
  }
}

const bus = new Bus();
bus.consoleHello(); // hello

위와 같이 생성한 추상 클래스를 상속받아 구체적인 구현을 하는 문법과 추상 클래스에서의 직접 구현을 모두 지원한다.

abstract class BusTime {
  abstract arrivalTime: () => number;
}

class Bus extends BusTime {
  arrivalTime: () => number = () => {
    return new Date().getMinutes();
  }
}

또 다른 예제로 위와 같이 추상 클래스 BusTime을 생성하고 이를 상속받아 실제 구현을 할 수 있다.

다만, 위의 코드는 자바스크립트로 변환되며 쓸모없는 코드를 생성한다.

"use strict";
class BusTime {
}
class Bus extends BusTime {
    constructor() {
        super(...arguments);
        this.arrivalTime = () => {
            return new Date().getMinutes();
        };
    }
}

위의 변환된 자바스크립트 코드를 보면, 추상 클래스 BusTime은 무의미한 클래스가 되어버린다.

그리고 Bus는 이 빈 클래스를 상속받는 식으로 타입스크립트는 변환된다.

 

Private

타입스크립트는 java와 같은 객체지향언어처럼 private, public, protected 접근 제한자를 지원해준다.

그리고 자바스크립트에서 #을 붙여 클래스 외부에서 접근이 불가능한 변수를 만들 수 있다.

class MyBus {
  public driver = "Jamie";
  #busId = "javascript private";
  private driverId = "typescript private";
}

const myBus = new MyBus();
console.log(myBus.driver);

myBus.#busId;
// Property '#busId' is not accessible outside class 'MyBus' because it has a private identifier.(18013)

myBus.driverId;
// Property 'driverId' is private and only accessible within class 'MyBus'.(2341)

🥒 #은 자바스크립트 문법이기에 런타임에서 에러가 발생하고, 타입스크립트 문법인 private는 컴파일 단계에서 에러가 발생한다.

 

다만, 우회를 통해서 private 타입스크립트가 자바스크립트로 컴파일 되면, 그 뒤로는 제약사항이 사라지기에 더 강력한 접근 제한을 위해서는 #을 사용할 수 있다.

"use strict";
var _MyBus_busId;
class MyBus {
    constructor() {
        this.driver = "Jamie";
        _MyBus_busId.set(this, "javascript private");
        this.driverId = "typescript private";
    }
}
_MyBus_busId = new WeakMap();
const myBus = new MyBus();
console.log(myBus.driver);

🫑 위 타입스크립트는 자바스크립트가 되면서 private 키워드가 사라진다.