우리는 한다, 개발을.

Typescript Class

⌛ 9 mins

Typescript Class

Typescript는 Javascript를 객체지향적 프로그램 기법을 사용할 수 있게 해줍니다.
그 중 class를 설명 드리겠습니다. Typescript의 class는 기존 객체지향언어인 java, C#의 class와 상당히 비슷하여
사용해보셨다면 익숙한 부분을 많이 느끼실 수 있습니다.

Class란?

class(클래스)란 객체 지향 프로그래밍에서 객체를 만들기 위한 틀,
객체의 상태(변수들)와 행동(메소드)가 정의된 곳

ex) 붕어빵틀에 재료와 행동에 따라 다른 결과물의 붕어빵(팥붕, 슈붕)을 만든다.
붕어빵틀 -> 클래스
굽다 -> 메소드
붕어빵 -> 객체

예제 코드는 게임을 가정하여 작성하였습니다.

  • 선언
    class Enemy{
      //...멤버변수
      constructor(매개변수){
      }
      //...멤버들
    }
    
  • 생성
    const enemy:Enemy = new Enemy();
    

생성자

인스턴스가 생성될 때 호출되는 초기화 메소드
인스턴스 생성 시에 실행되어야 할 작업이나 초기값을 주기 위해서 사용된다.
인스턴스를 생성할 때 파라미터로 값을 넘겨 받을 수 있다.

class Enemy{
    hp:number;
    power:number;
    type:string;
    constructor(hp:number, power:number, type:string){
        this.hp=hp;
        this.power=power;
        this.type=type;
        console.log("적군 초기화");
    }
}
const lv1Enemy = new Enemy(30,2, '몬스터'); // 생성과 동시에 생성자 실행 됨 "적군 초기화"

클래스의 멤버에 접근 하기위해선 this를 사용한다.

접근 제어자

Typescript엔 세가지의 접근제어자가 있다. 묵시적 타입은 public이다.

public : 모든 접근 허용
protected : 상속받은 클래스내에서만 접근 허용
private : 클래스 내에서만 접근 허용

class Enemy{
    public hp:number;
    protected power:number;
    private _type:string;
    constructor(hp:number, power:number, type:string){
        this.hp=hp;
        this.power=power;
        this._type=type;
    }
    public attack(){
        console.log(`${this._type}으로 부터 ${this.power} 만큼의 공격을 받았습니다!`);
    }
    private _run(){
        console.log("도망감");
    }
}

const lv1Enemy = new Enemy(30,2,'몬스터');
console.log(lv1Enemy.hp) // 30
console.log(lv1Enemy.power) // error : 접근제한 에러
console.log(lv1Enemy._type) // error : 접근제한 에러

class Boss extends Enemy{
    //멤버변수 생략
    constructor(hp:number, power:number, type:string, ultimatePower:number){
        super(hp, power, type);
        super.attack(); // "type 으로 부터 power 만큼의 공격을 받았습니다!"
        super._run(); // error : 접근제한 에러
        
    }
}

TypeScript 상에서는 접근 제어자에 따라 접근 또는 차단을 제어할 수 있지만,컴파일된 JavaScript는 접근 제어자를 지원하지 않는다.
때문에 실행시 private로 선언된 멤버도 호출 되어 실행된다.

상속

부모클래스로부터 상속을 받아 자식 클래스에서 부모의 멤버를 사용할 수 있다. 부모클래스의 생성자 매개변수는 super()로 전달할 수 있다.

class Enemy{
    private _hp:number;
    private _power:number;
    private _type:string;
    private _range:number;
    constructor(hp:number, power:number, type:string){
        this._hp=hp;
        this._power=power;
        this._type=type;
    }
    public attack(){
        console.log(`${this._type}으로 부터 ${this._power} 만큼의 공격을 받았습니다!`);
    }
}

class Boss extends Enemy{
//멤버변수 생략
    constructor(hp:number, power:number, type:string, ultimatePower:number){
        super(hp, power, type);
        this.ultimatePower = ultimatePower;
    }
    public ultimateSkill(){ //보스만의 새로운 행위
        console.log('보스 궁극기 사용! 데미지 : ',this.ultimatePower);
    }
}
const boss = new Boss(1000,100, '보스', 300);
boss.attack(); // "보스로 부터 100 만큼의 공격을 받았습니다!"
boss.ultimateSkill(); // "보스 궁극기 사용! 데미지 : 300"

위와 같이 공통적인 행동은 Enemy 클래스에 보스만의 특별한 행동은 Boss 클래스에 정의하여
Enemy 클래스를 상속받아 Boss 클래스는 부모인 Enemy 클래스에 정의된 attack 메소드를
중복으로 정의할 필요 없이 사용할 수 있습니다. (private로 선언된 메소드는 사용 X)

getter setter

TypeScript는 객체의 멤버에 대한 접근을 getter/setter로 접근할 수 있다.
이를 통해 각 객체의 멤버에 접근하는 방법을 세밀하게 제어할 수도 있다.

class Enemy{
    private _hp:number;
    private _power:number;
    private _type:string;
    private _range:number;
    constructor(hp:number, power:number, type:string, range:number){
        this._hp=hp;
        this._power=power;
        this._type=type;
        this._range=range;
    }
    public attack(){
        console.log(`${this._type}으로 부터 ${this._power} 만큼의 공격을 받았습니다!`);
    }
    set range(range:number){
        if(range<100) this._range = range;
    }
    get range(){
        return this._range;
    }
}

class Boss extends Enemy{
    //멤버변수 생략
    constructor(hp:number, power:number, type:string, ultimatePower:number){
        super(hp, power, type);
        this.ultimatePower = ultimatePower;
    }
        public ultimateSkill(){ //보스만의 새로운 행위
            super.range = 10;
            console.log('보스 궁극기 사용! 데미지 : ',this.ultimatePower, "사정거리 : ", super.range);
    }
}
const boss = new Boss(1000, 100, '보스', 300, 5);
boss.attack(); // "보스로 부터 100 만큼의 공격을 받았습니다!"
boss.ultimateSkill(); // "보스 궁극기 사용! 데미지 : 300 사정거리 : 10"

boss.range = 99;
console.log(boss.range) // 99

추상클래스

일부 메소드가 구현되지 않고 선언만 되어있는 클래스로 abstract가 선언된 메소드는 자식 클래스에서 반드시 구현되어야 한다.

abstract class Character {
    protected constructor(public name: string) {
    }
    printName(): void {
        console.log("캐릭터 아이디 : " + this.name);
    }
    abstract move(): void
    protected abstract attack():void;
    abstract skill():void
}
class Wizard extends Character {
    constructor(name:string) {
        super(name);
    }
    move(): void {
        console.log("캐릭터가 이동합니다.");
    }
    attack(): void {
        console.log("캐릭터가 공격합니다.");
    }
    skill():void{
        console.log("얼음공격을 사용합니다.");
    }
}
class Warrior extends Character {
    constructor(name:string) {
        super(name);
    }
    move(): void {
        console.log("캐릭터가 이동합니다.");
    }
    attack(): void { 
        console.log("캐릭터가 공격합니다.");
    }
    /* skill():void {
        console.log("핵주먹을 사용합니다.");
    }*/ // error 추상클래스에 정의된 abstract메소드는 반드시 정의 해야함
}
const wizard = new Wizard("이은결");
wizard.printName(); // "캐릭터 아이디 : 이은결"
wizard.move(); // "캐릭터가 이동합니다."
wizard.attack(); // "캐릭터가 공격합니다."
wizard.skill(); //"얼음공격을 사용합니다."
const warrior = new Warrior("정찬성")
warrior.printName(); // "캐릭터 아이디 : 이은결"
warrior.move(); // "캐릭터가 이동합니다."
warrior.attack(); // "캐릭터가 공격합니다."
warrior.skill(); //"핵주먹을 사용합니다."

참고 사이트
https://typescript-kr.github.io/pages/classes.html
https://velog.io/@jun094/TypeScript-Class