Classes
this Types
this를 타입으로 활용할 수 있습니다.
예를 들어 this를 반환하는 함수를 가진 부모 클래스와 자식 클래스가 있을 때, 각 반환 타입은 부모 클래스가 아닌 각각 클래스가 반환됩니다.
class P {
func() {
return this;
}
}
class C extends P {}
const p = new C();
const test = p.func(); // test의 타입은 P가 아닌 C입니다.
비슷한 방식으로 타입 표기를 this로도 할 수 있는데, 이 경우에는 this에 해당하는 타입만 사용할 수 있습니다.
class P {
dfFunc(val:P) {}
func(val: this) {}
}
class C extends P {}
const p = new P();
const c = new C();
c.dfFunc(p); // no error
c.func(p); // error C 타입만 인자로 사용할 수 있습니다.
this -based type guards
반환 타입을 작성하는 부분에 this is <Type>에 해당하는 구문을 사용하면 narrowing으로 사용할 수 있습니다.
class Box {}
class Circle {}
class Test {
isBox(): this is Box {
return this instanceof Box;
}
isCircle(): this is Circle {
return this instanceof Circle;
}
}
const test = new Test();
if(test.isBox()) {
// 해당 블록 안에서 test는 Box 타입
console.log('this is box');
} else if(test.isCircle()) {
// 해당 블록 안에서 test는 Circle 타입
console.log('this is circle');
}
특정 필드의 lazy validation에서 흔하게 사용됩니다. 예를 들어 Set의 has()와 비슷한 함수의 반환 타입으로 사용할 수 있습니다.
Parameter Properties
TS에서는 클래스 생성자의 파라미터를 같은 이름으로 속성(필드)을 생성해 줍니다.
class Test {
constructor(
public readonly x: number;
protected y: string;
private z: number;
) {}
}
const t = new Test(1, '2', 3);
console.log(t.x); // 1
클래스 문법을 자주 사용하지 않아 기존 JS에서도 제공해 주는 기능 아니야?라는 의문이 들어서 직접 해봤습니다.
class Test { cconstructor(x,y,z) {} } const t = new Test(1, '2', 3); console.log(t.x); // undefined console.log(t.y); // undefined console.log(t.z); // undefined
JS에서는 클래스의 속성으로 만들기 위해서 생성자 내부에 this의 속성으로 초기화해야 합니다.
class Test { constructor(x,y,z) { this.x = x; this.y = y; this.z = z; } } const t = new Test(1, '2', 3); console.log(t.x); // 1 console.log(t.y); // '2' console.log(t.z); // 3
Class Expressions
클래스는 함수 식과 비슷하게 사용할 수 있습니다.
const className = class<T> {
some:T;
constructor(val: T) {
this.some = val;
}
}
const c = new className('class expressions');
Constructor Signatures
JS의 클래스는 new 연산자를 사용해 인스턴화합니다. 해당 인스턴스에 대한 타입은 유틸리티 타입인 InstanceType을 활용할 수 있습니다.
class Test {}
const instance = new Test();
type TestInstance = InstanceType<typeof Test>;
const func = (test: TestInstance) {};
단순하게 Test를 타입으로 사용하지 않고 InstanceType<typeof Test>를 사용하는 이유는 무엇일까? 가독성을 위함인가?
위 코드에서 Test를 사용하거나 InstanceType을 사용하는 것은 차이가 없을 수 있습니다. 하지만 InstanceType의 진정한 목적은 클래스의 타입을 모를 때 사용하는 용도로 사용됩니다.
또한 IstanceType 내부에 들어가는 타입은 생성자 함수가 포함되어 있어야 하기 때문에 'typeof 클래스'를 사용합니다.
Test는 인스턴스 타입, typeof Test는 생성자 함수 타입, InstanceType<typeof Test>는 인스턴스 타입 추론
abstract Classes and Members
추상 클래스를 구현하는 것은 abstract 키워드를 사용하면 가능합니다. 추상 클래스는 클래스의 틀을 알려주는 것이라고 볼 수 있습니다. 추상 메서드가 있다는 것을 알려주지만 실제 구현 내용은 담겨있지 않습니다.
추상 클래스를 사용하기 위해서 extends로 새로운 클래스를 만들면서 추상 메서드를 구현해야 해당 클래스의 인스턴스를 만들어야 사용할 수 있습니다.
추상 멤버가 없는 클래스는 concrete 클래스라고 합니다.
Abstract Construct Signatures
추상 클래스에서 파생된 클래스의 생성자 함수를 사용하고 싶을 때가 있습니다. 위에서 봤듯이 'typeof 클래스'가 생성자 함수의 타입을 의미합니다.
하지만 추상 클래스는 조금 다릅니다. 인스턴스를 생성할 수 없기 때문입니다.
function Func(ctor: typeof AbClass) {
const instance = new ctor(); // error 추상 클래스는 인스턴스를 생성할 수 없다.
]
그렇기 때문에 추상 클래스의 생성자 함수를 사용하고 싶다면 아래와 같이 작성해야 합니다. 하지만 결국 해당 인자로 추상 클래스를 사용할 수 없습니다.
function Func(ctor: new () => Test) {
const instance = new ctor();
}
Func(Derived);
Func(Test); // error
Relationships Between Classes
대부분 TS에서 클래스는 구조를 비교하기 때문에 다른 클래스라도 같은 멤버를 가지고 있다면 혼용해서 사용할 수 있습니다. 다른 상속관계가 없다면 포함 관계(subtype relationships)도 가능합니다.
class A {
x = 0;
}
class B {
x = 1;
}
class C {
x = 2;
y = 0;
}
const t: A = new B();
const t2: A = new C();
그렇기 때문에 클래스는 supertype이 될 수 있고, 사용하지 않도록 주의해야 합니다.
참고
https://www.typescriptlang.org/docs/handbook/2/classes.html#this-types
'개발 > TS' 카테고리의 다른 글
| [TS] TS Doc Reference 1회독 (0) | 2025.07.16 |
|---|---|
| [TS] TS Doc Handbook 1회독 - 10 (0) | 2025.07.03 |
| [TS] TS Doc Handbook 1회독 - 8 (0) | 2025.06.20 |
| [TS] TS Doc Handbook 1회독 - 7 (0) | 2025.06.17 |
| [TS] TS Doc Handbook 1회독 - 6 (0) | 2025.06.16 |