클래스 Class
typescript 클래스는 클래스 몸체에 클래스 프로퍼티를 사전 선언하여야 한다.
class Animal {
// 클래스 프로퍼티를 사전 선언하여야 한다
name: string;
constructor(name: string) {
// 클래스 프로퍼티에 값을 할당
this.name = name;
}
status() {
console.log(`${this.name} is cute.`);
}
}
const animal = new Animal('Dog');
animal.status(); // Dog is cute.
클래스 Animal 은 세 개의 멤버를 가지고 있다. name 프로퍼티, 생성자constructor, status 메소드이다. 클래스 안에서 클래스의 멤버를 참조할 때 this 를 앞에 붙인다. 이는 멤버에 접근하는 것을 의미한다.
const animal = new Animal('Dog');
에서 new 는 Animal 클래스의 인스턴스를 생성한다. 이 코드는 이전에 정의한 생성자를 호출하여 Animal 형태의 새로운 객체를 만들고, 생성자를 실행하여 초기화한다.
상속 Interitance
typescript 기본 타입 정의에서 설명하였듯, 인터페이스는 extends 라는 키워드를 사용하여 이미 존재하는 클래스를 확장하고 상속할 수 있다. 이는 클래스도 마찬가지이다.
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}
// Dog 클래스는 Animal 클래스를 상속 받았기 때문에 bark()와 move()를 모두 가진 Dog 인스턴스를 생성할 수 있다.
class Dog extends Animal {
bark() {
console.log('Woof! Woof!');
}
}
const dog = new Dog();
dog.bark(); // Woof! Woof!
dog.move(10); // Animal moved 10m.
위의 코드에서 Dog 은 Animal 이라는 상위super 클래스에서 파생된 하위sub 클래스이다.
조금 더 심화된 코드를 보자.
// Animal 클래스는 name 이라는 프로퍼티와 생성자, move 라는 메소드를 가진다.
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
// Snake 클래스는 Animal 클래스의 하위 클래스이다.
class Snake extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 5) {
super.move(distanceInMeters);
}
}
// Horse 클래스는 Animal 클래스의 하위 클래스이다.
class Horse extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 45) {
super.move(distanceInMeters);
}
}
let sam = new Snake("Sammy the Python");
let jain: Animal = new Snake("Jain the Python")
let tom: Animal = new Horse("Tommy the Palomino");
sam.move(); // Sammy the Python moved 5m.
jain.move(10); // Jain the Python moved 10m.
tom.move(34); // Tommy the Palomino moved 34m.
위 코드를 살펴보면 파생된 클래스 Snake 와 Horse 의 생성자 함수는 상위 클래스 Animal 의 생성자를 실행하기 위해서 super() 를 호출해야 한다.
기초 클래스의 메소드를 하위 클래스에 오버라이드 하는 방법도 볼 수 있다. 기초 클래스에서는 move 메소드의 값을 0 으로 지정하였지만, Snake 와 Horse 클래스는 이를 오버라이드해서 각각 5와 45로 지정하였다. Snake의 클래스 인스턴스 sam 에 move 메소드를 붙인 sam.move();
는 파라미터로 아무 값도 넘겨주지 않아 오버라이드 한 값 5를 출력하였지만, 마찬가지로 Snake 의 클래스 인스턴스 jain 에 move 메소드를 붙인 jain.move(10);
은 10이라는 파라미터로 오버로딩 되어 10을 출력한다.
아래의 코드로 보면 조금 더 이해하기 쉽다.
class A {
move(x:number = 0){
console.log(x);
}
}
class B extends A {
move(x:number = 5){
console.log(x);
}
}
let a = new A();
let b = new B();
a.move(); // 0
b.move(); // 5 .. overriding
a.move(10); // 10 .. overloading
b.move(10); // 10 .. overloading
접근제한자 Access modifiers
접근제한자Access modifiers 는 클래스의 메소드나 프로퍼티의 가시성visibility 을 변경해준다.
다른 클래스 기반 객체 지향 언어가 사용하는 접근 제한자 public, protected, private 를 지원하며 의미 또한 기본적으로 동일하나, 접근 제한자를 명시하지 않았을 때 protected 로 지정되는 다른 클래스 기반 언어들과는 달리 typescript 는 암묵적으로 public 이 선언된다.
접근제한자의 종류
접근 가능성 | public | protected | private |
클래스 내부 | O | O | O |
자식 클래스 내부 | O | O | X |
클래스 인스턴스 | O | X | X |
아래의 코드를 ts 파일에 붙여넣으면 접근 제한자가 어떻게 기능하는지 빨간 줄을 통해 확인할 수 있다.
class Foo {
public x: string;
protected y: string;
private z: string;
constructor(x: string, y: string, z: string) {
// public, protected, private 접근 제한자 모두 클래스 내부에서 참조 가능하다.
this.x = x;
this.y = y;
this.z = z;
}
}
const foo = new Foo('x', 'y', 'z');
// public 접근 제한자는 클래스 인스턴스를 통해 클래스 외부에서 참조 가능하다.
console.log(foo.x);
// protected 접근 제한자는 클래스 인스턴스를 통해 클래스 외부에서 참조할 수 없다.
console.log(foo.y);
// error TS2445: Property 'y' is protected and only accessible within class 'Foo' and its subclasses.
// private 접근 제한자는 클래스 인스턴스를 통해 클래스 외부에서 참조할 수 없다.
console.log(foo.z);
// error TS2341: Property 'z' is private and only accessible within class 'Foo'.
// extends 를 이용해 클래스 Foo 를 상속받은 자식 클래스 Bar
class Bar extends Foo {
constructor(x: string, y: string, z: string) {
super(x, y, z);
// public 접근 제한자는 자식 클래스 내부에서 참조 가능하다.
console.log(this.x);
// protected 접근 제한자는 자식 클래스 내부에서 참조 가능하다.
console.log(this.y);
// private 접근 제한자는 자식 클래스 내부에서 참조할 수 없다.
console.log(this.z);
// error TS2341: Property 'z' is private and only accessible within class 'Foo'.
}
}
접근 제한자는 생성자 파라미터에도 선언할 수 있다. 이때 ,접근 제한자가 사용된 생성자 파라미터는 생성자 내부에서 별도의 초기화가 없어도 암묵적으로 초기화가 수행된다.
class Foo {
/*
접근 제한자가 선언된 생성자 파라미터 x는 클래스 프로퍼티로 선언되고 자동으로 초기화된다.
public이 선언되었으므로 x는 클래스 외부에서도 참조가 가능하다.
*/
constructor(public x: string) { }
}
const foo = new Foo('Hello');
console.log(foo); // Foo { x: 'Hello' }
console.log(foo.x); // Hello
class Bar {
/*
접근 제한자가 선언된 생성자 파라미터 x는 멤버 변수로 선언되고 자동으로 초기화된다.
멤버변수란 클래스 내에서 선언되는 변수를 의미한다.
private이 선언되었으므로 x는 클래스 내부에서만 참조 가능하다.
*/
constructor(private x: string) {
console.log(this.x); // Hello
}
}
const bar = new Bar('Hello');
console.log(bar); // Bar { x: 'Hello' }
// private이 선언된 bar.x는 클래스 내부에서만 참조 가능하다
console.log(bar.x); // Property 'x' is private and only accessible within class 'Bar'.
클래스 상속 시, 클래스의 모든 멤버(public, protected, private)가 상속되지만 구현까지 상속하지는 않는다
readonly
typescript 는 readonly 접근 제한자를 추가로 지원한다. 클래스의 속성에 readonly 키워드를 사용하면 프로퍼티에 변경할 수 없는immutable 속성을 선언하여 값을 할당할 수 없고 오로지 접근 및 읽기만 가능하다.
class Foo {
private readonly MAX_LEN: number = 5;
private readonly MSG: string;
constructor() {
this.MSG = 'hello';
}
log() {
// readonly가 선언된 프로퍼티는 재할당이 금지된다.
this.MAX_LEN = 10; // Cannot assign to 'MAX_LEN' because it is a constant or a read-only property.
this.MSG = 'Hi'; // Cannot assign to 'MSG' because it is a constant or a read-only property.
console.log(`MAX_LEN: ${this.MAX_LEN}`); // MAX_LEN: 5
console.log(`MSG: ${this.MSG}`); // MSG: hello
}
}
new Foo().log()
readonly 와 const 의 차이는 어디에 사용할지에 있다. const 는 변수에 사용하고 readonly 에는 프로퍼티에 사용한다.
접근자
typescript 는 객체가 특정 속성에 접근하고 할당하는 것에 대해 제어할 수 있다. 접근을 제한하는 접근제한자가 있다면 접근을 할 수 있도록 하는 접근자가 존재할수도 있다는 뜻이다.
획득자getter 와 설정자setter 는 객체의 멤버에 대한 접근을 가로채는 방식을 의미한다. 이를 통해 각 객체의 멤버에 접근하는 방법을 세밀하게 제어할 수 있을 뿐만 아니라 private 설정 된 속성에 접근하여 값을 읽거나 쓰기 위한 getter / setter 함수를 사용할 수 있다.
getter 와 setter 는 말 그대로 어떤 객체 혹은 변수의 값을 가져오거나 설정해주는 역할을 하는 메소드를 의미한다. getter 메소드는 프로퍼티를 읽으려고 할 때 실행되고 setter 는 값을 할당하려고 할때 사용된다. get 으로 가져오고 set 으로 설정한다고 생각하면 된다.
class Person {
private _name: string | null = null;
private _age: number
// 여기에서 Person 의 private 프로퍼티인 _name 을 가져온다
get name(): string {
return this._name;
}
// 위에서 가져온 _name 에 조건 값을 할당한다
set name(value:string) {
if ( value.length > 3 ) {
this._name = value;
}
}
}
/* 인스턴스 생성 ------------------------------------------------ */
let person = new Person();
console.log(person.name); // null
person.name = 'sue';
console.log(person.name); // null .. string 이 되려면 3보다 커야 한다
person.name = 'choi sue';
console.log(person.name); // choi sue
참고로 ECMAScript 5 이상을 출력하도록 컴파일러를 설정해야한다. tsc -t es5 filename.ts 명령어를 실행하여 컴파일하면 된다.
'typescript' 카테고리의 다른 글
typescript (0) | 2021.07.26 |
---|