Typescript 기초(4) – Class

Typescript Handbook / Developer’s Record 를 참고했습니다.

기본

class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    return `안녕 ${this.greeting}`;
  }
}

let 병인이: Greeter = new Greeter("만나서 반가워");
console.log(병인이.greet()); // 안녕 만나서 반가워

상속

class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  move(distance: number) {
    console.log(`${this.name} moved ${distance}`);
  }
}

class Snake extends Animal {
  constructor(name: string) {
    super(name);
  }
  move(distance: number = 15) {
    console.log(`스....~...스윽... 거리며 ${distance}m 움직였다`);
    super.move(distance)
  }
}

class Horse extends Animal {
  constructor(name: string) {
    super(name);
  }
  move(distance: number = 20) {
    console.log(`히히힝히잉히이이잉히잉 거리며 ${distance}m 움직였다`);
    super.move(distance);
  }
}

let 나뱀: Snake = new Snake("걍뱀");
let 나말: Horse = new Horse("양말");
나말.move(22);
// 히히힝히잉히이이잉히잉 거리며 22m 움직였다
// 양말 moved 22

접근 제어

public

class Animal {
  public name: string;
  public constructor(name: string) {
    this.name = name;
  }
  public move(distance: number) {
    console.log(`${this.name} moved ${distance}`);
  }
}

protected

class Person {
  protected name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Employee extends Person {
  public department: string;
  constructor(name: string, department: string) {
    super(name);
    this.department = department;
  }
  introduce() {
    console.log(`Hello, my name is ${this.name} and I work in ${this.department}`);
  }
}

let employee: Employee = new Employee("윤병인", "개발부서");
employee.introduce(); // Hello, my name is 윤병인 and I work in 개발부서

Person을 바로 intialize하면 name에 접근 할 수 없다.

class Person {
  protected name: string;
  constructor(name: string) {
    this.name = name;
  }
}

let person: Person = new Person("윤병인");
person.name; // error : Property 'name' is protected and only accessible within class 'Person' and its subclasses.ts(2445)

private

class Animal {
  name: string;
  private sex: string;
  constructor(name: string, sex: string) {
    this.name = name;
    this.sex = sex;
  }
  move(distance: number) {
    console.log(`${this.name} moved ${distance}m`);
  }
}

let dog: Animal = new Animal("강아쥐", "수컷");
console.log(dog.name);
console.log(dog.sex); // Property 'sex' is private and only accessible within class 'Animal'

호환문제

class Animal {
  public name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Paper {
  public name: string;
  constructor(name: string) {
    this.name = name;
  }
}

let animal: Animal = new Animal("걍동물");
let paper: Paper = new Paper("걍종이");
animal = paper;
console.log(animal.name); // 걍종이

구조가 같으면 할당이 된다!

class Animal {
  public name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }
  bark() {
    console.log("멍! 멍! 멍! 멍!");
  }
}

let animal: Animal = new Animal("걍동물");
let dog: Dog = new Dog("개자슥");

animal = dog;
console.log(animal.name); // 개자슥
animal.bark(); // error : Property 'bark' does not exist on type 'Animal'.

하지만, 그렇다고 없던걸 쓸 수 있는건 아니다. 마치 Typecasting느낌이랄까..

Readonly

class Octopus {
  name: string;
  readonly numberOfLegs: number = 8;
  constructor(name: string) {
    this.name = name;
  }
}

let dad: Octopus = new Octopus("우리아부지");
console.log(dad.name);
console.log(dad.numberOfLegs);
dad.numberOfLegs = 2; // error : Cannot assign to 'numberOfLegs' because it is a read-only property

Parameter Property

class Octopus {
  readonly numberOfLegs: number = 8;
  constructor(public name: string, private secret: string) {}
}

let dad: Octopus = new Octopus("우리아부지", "대머리");
console.log(dad.name); // 우리아부지

이거 편하다. 인자값 앞에 접근제한자를 붙이면 된다.

Getter/Setter

let passcode = "secret passcode";
class Employee {
  constructor(private _fullName: string) {}
  get fullName(): string {
    console.log("you're trying to get fullName");
    return this._fullName;
  }
  set fullName(newName: string) {
    console.log(`you're trying to set fullName as ${newName}`);
    if (passcode && passcode == "secret passcode") {
      this._fullName = newName;
    } else {
      console.log("Error : check your passcode first");
    }
  }
}

let employee: Employee = new Employee("Jin Macho");
employee.fullName // you're trying to get fullName
employee.fullName = "Bob Smith"; // you're trying to set fullName as Bob Smith

그닥 쓸모있어 보이지는 않는다.

Static

class Grid {
  static origin = {x: 0, y: 0};
  constructor(public scale: number) {}
  calculateDistanceFromOrigin(point: {x: number, y: number}) {
    let xDist = (point.x - Grid.origin.x);
    let yDist = (point.y - Grid.origin.y);
    return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
  }
}

let grid: Grid = new Grid(1.0);
console.log(grid.calculateDistanceFromOrigin({x: 10, y: 20})); // 22.360679774997898

Abstract

abstract class Animal {
  abstract makeSound(): void;
  move(): void {
    console.log("Move ... Move !");
  }
}

let animal: Animal = new Animal(); // error : Cannot create an instance of an abstract class.

그 자체로 initialize는 안된다.

abstract class Department {
  constructor(public name: string) {}
  printName(): void {
    console.log(`Department name: ${this.name}`);
  }
  abstract printMeeting(): void;
}

class AccountingDepartment extends Department {
  constructor(name: string) {
    super(name);
  }
  printMeeting(): void {
    console.log("Meeting in on 10am");
  }
  generateReports() {
    console.log("Generating Reports");
  }
}

let depatment: AccountingDepartment = new AccountingDepartment("ACD");
depatment.printName(); // ACD
depatment.printMeeting(); // Meeting in on 10am

abstract keyword가 붙은 거는 꼭 상속받는 sub class에서 정의해줘야한다.

생성자함수

너무 길어서 다음번에 해야겠다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다

Up Next:

Typescript 기초(3) – Interfaces

Typescript 기초(3) – Interfaces