4 분 소요

1. 클래스란?

  • Object를 만드는 설계도
  • 클래스 이전에 object를 만드는 기본적인 방법은 function
  • Javascript에도 class는 ES6부터 사용 가능
  • OOP을 위한 초석
  • Typescript에서는 class도 사용자가 만드는 타입의 하나
# 프로젝트 생성

$ mkdir ts-class
$ cd ts-class
$ npm init -y
$ npm i typescript -D
$ npx tsc --init


// example.ts

// 간단한 Class 만들기 1
class Person { }

const p1 = new Person();
console.log(p1);  // Person {}


# 컴파일

$ npx tsc
$ node example.ts


// example.js

// es5
"use strict";
var Person = /** @class */ (function () {
    function Person() {
    }
    return Person;
}());
var p1 = new Person();
console.log(p1);


// tsconfig.json

// 컴파일 es6 변경
"target": "es6"


// example.js

// es6
"use strict";
class Person {
}
const p1 = new Person();
console.log(p1);


// example.ts

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

const p2 = new Person("LWW");
console.log(p2);  // Person { name: 'LWW' }


  • class 키워드를 이용하여 class를 만들 수 있음
  • class 이름은 보통 대문자를 이용
  • new를 이용하여 class를 통해 object를 만들 수 있음
  • constructor를 이용하여 object를 생성하면서 값을 전달할 수 있음
  • this를 이용해서 만들어진 object를 가리킬 수 있음
  • Javascript로 컴파일되면 ES5의 경우 function으로 변경됨


2. Constructor & Initialize

  • 생성자 함수가 없으면, 디폴트 생성자가 불림
  • 개발자가 만든 생성자가 하나라도 있으면, 디폴트 생성자는 사라짐
  • strict 모드에서 property를 선언하는 곳 또는 생성자에서 값을 할당해야 함
  • peoperty를 선언하느 곳 또는 생성자에서 값을 할당하지 않는 경우에는 !를 붙여서 위험을 표현
  • class의 property가 정의되어 있지만, 값을 대입하지 않으면 undefined
  • 생성자에는 async를 설정할 수 없음
// example.ts

class Person {
  name: string = 'LWW';
  age!: number;

  constructor(age?: number) {
    if (age === undefined) {
      this.age = -1;
    } else {
      this.age = age;
    }
  }

  async init() {

  }
}

const p3: Person = new Person(29);
const p4: Person = new Person();

console.log(p3);  // Person { name: 'LWW', age: 29 }
console.log(p3.age);  // 29
console.log(p4);  // Person { name: 'LWW', age: -1 }


3. 접근 제어자

  • 접근 제어자에는 public, private, protected가 있음
  • 설정하지 않으면 public
  • 클래스 내부의 모든 곳(생성자, 프로퍼티, 메서드)에 설정 가능
  • private으로 설정하면 클래스 외부에서 접근할 수 없음
  • Javascript에서는 private를 지원하지 않아 이름 앞에 _를 붙여서 표현했음


4. Initialization in Constructor Parameters

  • 생성자의 Parameter를 받아 그 클래스에 Property로 초기화 하는 방법
// example.ts

class Person {
  public constructor(public name: string, private age: number) { }
}

const p5: Person = new Person("LWW", 29);
console.log(p5);  // Person { name: 'LWW', age: 29 }


4. Getters, Setters

// example.ts

class Person {
  public constructor(private _name: string, private age: number) { }

  get name() {
    console.log('get');
    return this._name + " 입니다.";
  }

  set name(n: string) {
    console.log('set');
    this._name = n;
  }
}

const p6: Person = new Person("LWW", 29);

// get을 하는 함수 getter
console.log(p6.name);  // get
                       // LWW 입니다.

// set을 하는 함수 setter
p6.name = 'Tom';  // set

console.log(p6.name);  // get
                       // Tom 입니다.


5. Readonly Property

  • Set은 불가, Get만 가능
  • Initialization 부분과 Constructor 안에서만 readonly property를 지정해 줄 수 있음
  • 다른 메서드 등에서는 Set할 수 없음
  • Property를 초기값으로 고정하고 다른 값으로 변경하고 싶지 않을 때, readonly를 붙여서 다른 개발자가 Set할 때 에러를 발생시킴
// example.ts

class Person {
  public readonly name: string = "LWW";
  private readonly country: string

  public constructor(private _name: string, private age: number) {
    this.country = "Korea";
  }

  hello() {
    this.country = "Japan";  // Error! 읽기 전용 속성이므로 ...
  }
}

const p6: Person = new Person("LWW", 29);

console.log(p7.name);
p7.name = 'Tom';  // Error! 읽기 전용 속성이므로 ...
console.log(p7.name);


6. Index Signatures in Class

  • Class 안에서 Index Signatures를 선언하고 사용하는 방법
  • Property가 고정된 형태가 아닐 때, 즉 동적으로 들어올 때 사용
// example.ts

class Students {
  // [index: string]: string;
  [index: string]: "male" | "female";
  LWW: "male" = "male"
}

const a = new Students();
a.LWW = "male";
a.Tom = "male";
console.log(a)  // Students { LWW: 'male', Tom: 'male' }

const b = new Students();
b.Amy = "female";
b.James = "male";
b.Anna = "female";
console.log(b)  // Students { Amy: 'female', James: 'male', Anna: 'female' }


7. Static Properties & Methods

// example.ts

class Person {
  private static CITY = "Seoul";

  public static sayHello() {
    console.log("안녕하세요.")
  }
  public hello() {
    console.log("Hi.", Person.CITY);
  }
  public change() {
    Person.CITY = 'Busan';
  }
}

const p8 = new Person();
Person.sayHello();  // 안녕하세요.
p8.sayHello();  // Error!
p8.hello();  // Hi. Seoul

const p9 = new Person();
p9.hello();  // Hi. Seoul
p8.change();
p9.hello();  // Hi. Busan


8. Singletons

// example.ts

class ClassName {
  private static instance: ClassName | null = null;

  public static getInstance(): ClassName {
    // ClassName으로부터 만든 object가 있으면 그걸 return
    // ClassName으로부터 만든 object가 없으면 만들어서 return
    if (ClassName.instance === null) {
      ClassName.instance = new ClassName();
    }
    return ClassName.instance;
  }

  private constructor() { }
}

const a = ClassName.getInstance();
const b = ClassName.getInstance();
const c = new ClassName();  // Error!

console.log(a === b);  // true


9. 상속

// example.ts

// Parent 클래스
class Parent {
  constructor(protected _name: string, private _age: number) { }

  public print(): void {
    console.log(`이름은 ${this._name} 이고, 나이는 ${this._age} 입니다.`);
  }

  protected printName(): void {
    console.log(this._name, this._age);
  }
}

const p = new Parent("LWW", 29);
p._age  // Error!
p._name  // Error!
p.print();  // 이름은 LWW 이고, 나이는 29 입니다.

// Child 클래스
class Child extends Parent {
  public gender = 'female';

  constructor(age: number) {
    super('LWW Jr.', age);
    this.printName();
  }
}

const c = new Child(5);  // LWW Jr. 5
c._age  // Error!
c._name  // Error!
c.gender
c.print();  // 이름은 LWW Jr. 이고, 나이는 5 입니다.


10. Abstract Classes

  • 상속을 이용해 class를 구조적으로 작성하는데 도움을 줌
// example.ts

abstract class AbstractPerson {
  protected _name: string = 'LWW';

  abstract setName(name: string): void;
}

const p1 = new AbstractPerson()  // Error!

class Person extends AbstractPerson {
  setName(name: string): void {
    this._name = name;
  }
}

const p2 = new Person();
console.log(p2);  // Person { _name: 'LWW' }
p2.setName('Tom');
console.log(p2);  // Person { _name: 'Tom'}

댓글남기기