클래스 (class)
클래스는 객체지향형 프로그래밍의 기본 단위로서 객체를 생성하는 템플릿과 같은 기능을 한다. JavaScript는 Prototype에 기초한 클래스 개념을 가지고 있는데, 이는 C#, Java와 같은 객체지향형 프로그래밍 언어를 사용하는 개발자에게 익숙하지 않은 개념이다. TypeScript에서는 C#, Java에서 사용하는 클래스 개념과 유사한 클래스를 사용하며, class 라는 키워드 사용하여 클래스를 구현한다.
TypeScript에서 클래스를 정의하는 간단한 예제를 먼저 들어 보면 아래와 같다.
class Shape { name: string; constructor(name: string) { this.name = name; } draw(x: number, y: number) { console.log("Draw " + this.name + " at " + x + "," + y); } }
위 예제는 Shape 라는 클래스를 정의한 것으로, 클래스는 기본적으로 속성(property)과 메서드(method)를 갖는다. 위 예제에서 name은 속성을 가리키며, draw()는 메서드를 가리킨다. constructor() 는 클래스 생성자를 가리키는 것으로, 객체를 생성할 때 호출되며, 클래스 멤버를 초기화하는 역활을 한다. 클래스의 메서드에서 다른 클래스 멤버(속성이나 메서드)를 엑세스하기 위해서는 this 키워드를 사용한다. 예를 들어, 위의 draw() 메서드 안에서 name 속성을 엑세스하기 위해서 this.name 과 같이 사용하였다. 클래스 내의 다른 메서드를 호출할 때도 마찬가지로 this.메서드명(...) 을 사용한다.
Shape 클래스로부터 객체를 생성하기 위해서는 new Shape(...)와 같이 호출하고, 이는 생성자(constructor)를 호출하게 된다. 생성된 객체를 갖는 변수로부터 클래스의 속성이나 메서드를 호출할 수 있다.
// Shape 객체 생성 및 사용 let s1 = new Shape("MyCircle"); s1.draw(100, 100);
접근제한자 (Access Modifier)
C#이나 Java에서와 같이 TypeScript에서는 클래스 멤버를 접근하는 범위를 지정하는 접근제한자(access modifier)를 가지고 있는데, TypeScript는 public, protected, private 등 3가지의 접근제한자를 갖는다.
public | public은 객체의 내,외부에서 해당 멤버(속성/메서드)를 모두 접근할 수 있다는 것을 표시한다. TypeScript의 클래스 멤버들은 디폴트로 모두 public이다. 즉, 별도로 접근제한자를 지정하지 않으면 public 멤버가 된다. |
protected | protected로 지정된 멤버는 해당 클래스와 그 클래스로부터 파생된 서브클래스들에서 사용될 수 있다. |
private | private으로 지정된 멤버는 해당 클래스 내에서만 사용될 수 있다. |
아래 예제에서 name은 private 멤버이고, x, y는 public 멤버이다. name은 클래스 외부에서 사용할 수 없으며, x, y는 외부에서 읽거나 쓰는 일을 할 수 있다. 그리고, draw()는 별도로 접근제한자를 지정하지 않아서 디폴트로 public 메서드가 된다.
class Shape { private name: string; public x: number = 0; public y: number = 0; constructor(name: string) { this.name = name; } draw() { console.log("Draw " + this.name + " at " + this.x + "," + this.y); } } let s1 = new Shape("MyCircle"); s1.x = 100; s1.y = 100; s1.draw(); // 에러: private은 접근 못함 // let name = s1.name;
Readonly Modifier
속성 앞에 readonly 라는 키워드를 적으면, 그 속은 읽기 전용이 된다. 읽기 전용 속성은 생성자나 속성 선언시 값이 지정되어야 한다. 아래 예제에서 id 는 readonly 속성으로 생성자에서 값을 지정하고 있고, empType은 속성 선언시 그 값을 할당하고 있다.
class Employee { // 생성자에서 id 지정한 후 읽기 전용 readonly id: number; dept: string; constructor(empId: number) { this.id = empId; } // 속성 선언시 값 지정 readonly empType: string = "FTE"; }
Getter와 Setter (Accessor)
클래스 속성을 엑세스하면서 필터링이나 간단한 체크를 수행할 때, 흔히 getter와 setter를 사용한다. TypeScript에서 getter를 사용하기 위해서는 메서드 앞에 get 키워드를 적으며, setter를 사용하기 위해서는 메서드 앞에 set 키워드를 적는다. 친 아래 예제는 Employee의 나이가 18세 미만인지를 setter에 체크하고 있다.
class Employee { private _age: number; get age(): number { return this._age; } set age(value: number) { if (value < 18) { throw new Error("Invalid age"); } this._age = value; } } let emp = new Employee(); emp.age = 25; console.log(emp.age);
Accessor (getter와 setter)를 사용하기 위해서는 tsc 컴파일러 타켓을 ES5 이상으로 설정한다.
정적 속성 (static property)
정적 속성은 객체가 아닌 클래스 소속의 속성을 가리키며, 속성 앞에 static 이라는 키워드를 붙여 사용한다. 인스턴스 속성은 "this.속성명" 을 통해 엑세스하였는데, 정적 속성을 "클래스명.속성명"을 사용하여 엑세스한다. 아래 예제에서 Cutline은 정적 속성으로 정의되어 있고, 클래스 내부 혹은 외부에서 Exam.Cutline을 사용하여 엑세스하고 있다.
class Exam { static Cutline: number = 80; scoreCheck(score: number) { if (score >= Exam.Cutline) { console.log("PASS"); } else { console.log("FAIL"); } } } let exam: Exam; exam = new Exam(); console.log("cutline: " + Exam.Cutline); exam.scoreCheck(85);