[TypeScript 기본 이론] #3 Class

mechaniccoder·2020년 7월 2일
0

TypeScript 기본이론

목록 보기
3/6
post-thumbnail

Introduction


기존 JS에서는 재사용 컴포넌트를 만들기 위해 함수, 프로토타입-기반 상속을 사용했어. 객체 지향방식에 익숙한 개발자는 굉장히 어색했을거야. 그러다, ES6부터 객체 지향의 클래스 기반 상속을 지원했기 때문에 TS에서는 이러한 기법들을 사용할 수가 있어.

클래스의 기본적인 개념과 상속에 대해서는 설명하지 않을게. 이미 잘 알고 있을거야. 대신 super()

호출하는 경우의 예시만 잠깐 살펴보자. 상위 클래스의 생성자를 실행하고 this키워드를 사용하기 위해서란거 이미 잘 알고있지?

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

class Dog extends Animal {
  constructor(name: string) {
    super(name); 
	}
  move(distance = 5) {
    super.move(distance);
  }
}

Public, Private and Protected Modifiers


Pulic

클래스에서 외부에 노출시켜도 되는 멤버들은 기본적으로 public이야. 굳이 사용하지 않아도 돼.

위에서 사용한 예제를 들어줄게.

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

ECMAScript Private Fields

TS 3.8 버전에서, 비공개 필드를 위한 새로운 문법이 추가됐어.

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

const dog = new Animal('dog');
dog.#name; // 에러, 비공개 식별자이므로 'Aniaml' 클래스 외부에서 접근할 수 없어.

Private

TS에서는 클래스 외부에서 멤버에 접근하지 못하도록 private으로 표현하는 방법도 있어.

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

class Dog extends Animal {
  constructor() {
    super('Dog');
  }
}

class Cat {
  private name: string;
  constructor(theName: string) { this.name = theName; }
}

const animal = new Animal('animal');
const dog = new Dog();
const cat = new Cat('cat');

animal = dog // 성공, 같은 private name 프로퍼티를 공유하기 때문이지
animal = cat // 에러, 형태는 같아도 private name이 선언된 곳이 다르지?

Protected

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

class Dog extends Animal {
  private age: number;
  constructor(name: string, age: number) {
    super(name);
    this.age = age;
  }

  introduce() {
    return `name is ${this.name}, age is ${this.age}`;
  }
}

const dog = new Dog('dog', 5);
console.log(dog.introduce());
console.log(dog.name); // 에러, 외부에서 접근할 수 없어.

여기서 살펴봐야 하는 점은 name 프로퍼티를 내부에서 사용하는 건 가능하지만 클래스 외부에서 인스턴스로 사용할 수 없다는 점이야. private과 차이점은 private은 프로퍼티를 포함하는 클래스에서만 접근이 가능하지만 protected는 그 클래스뿐만 아니라 하위 클래스에서도 접근이 가능해.

Readonly

처음에 생성자로 초기화하고 나서 변경할 수 없어.

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

const animal = new Animal('kelon');
animal.name = 'sudo'; // 에러, 읽기 전용이므로 수정할 수 없어

Parameter properties

매개변수의 선언과 할당을 한 번에 할 수도 있어. 앞에 키워드만 붙여주면 돼. private public protected readonly

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

class Animal {
  constructor(readonly name: string) { this.name}
}

위와 아래의 예제가 같겠지?

Accessors(접근자)

getter와 setter를 말해. 이미 ES6에서 공부한 내용이기 때문에 자세히 설명은 안할거야. getter와 setter는 마치 프로퍼티처럼 접근할 수 있다는 것만 알아두고 넘어가자.

const nameLength = 10;

class Animal {
  private _name: string;
  constructor() {
    this._name = '';
  };

  get name():string {
    return this._name;
  }

  set name(newName: string) {
    if ( newName && newName.length > nameLength) {
      throw new Error('name is too long');
    }
    this._name = newName;
  }
}

const animal = new Animal();
animal.name = 'kelly'; // setter를 활용해 _name에 값을 넣어주었어
console.log(animal.name); // kelly, getter가 호출돼서 _name을 반환했지

Static Properties(전역 프로퍼티)

인스턴스가 아닌 클래스 자체에서 전역 프로퍼티를 설정하고 싶으면 어떻게 할까? static을 활용하면 돼. 그리고 접근할 때는 인스턴스에서 this 키워드를 사용하는 것과 비슷하게 클래스 명을 사용해. (여기선 Animal)

class Animal {
  static age = 27;
  test() { return `${Animal.age}`}
}

const animal = new Animal();
animal.test();

Abstract Classes(추상 클래스)

추상 클래스는 다른 클래스들이 파생될 수 있는 기초 클래스이며, 직접 인스턴스화할 수 없고, 인터페이스와는 다르게 멤버의 세부 정보를 포함할 수 있어.

abstract class Animal {
  abstract makeSound(): void; // 추상 메서드, 반드시 하위 클래스에서 구현되어야 해
  move(): void {
    console.log('roaming the earth');
  }
}

abstract를 활용한 추상 메서드는 구현이 포함되지 않지만 반드시 하위 클래스에서 구현되어야만 해.

abstract class Animal {
  constructor(public name: string) {};

  abstract makeSound(): void;

  move(): void {
    console.log('roaming the earth');
  }
}

class Dog extends Animal {
  constructor() {
    super('kelly');
  }

  makeSound(): void {
    console.log('hello kelly');
  }

  handleProblem(): void {
    console.log('something is wrong');
  }
}

const lovvy = new Animal // 에러, 추상 클래스는 인스턴스화 하지 않아
const lovvy: Animal = new Dog();
lovvy.move();
lovvy.makeSound();
lovvy.handleProblem(); // 에러, Animal type에 포함되지 않는 메서드라서

References


profile
세계 최고 수준을 향해 달려가는 개발자입니다.

0개의 댓글