클래스 + 접근 제어자 — public·private·protected
class 에 타입 붙이기, 접근 제어, 생성자 단축 문법, abstract, implements.
JS 의 class 위에 TS 가 추가하는 것은 두 가지 — 필드/메서드에 타입, 그리고 접근 제어자(public/private/protected). 그 위에 abstract, implements, 생성자 단축 같은 편의 문법이 얹힙니다. 8편은 OOP 색이 진한 코드를 다룰 때 필요한 모두를 정리합니다.
기본 — 필드와 메서드 타입
class User {
// 필드 선언 + 타입
id: number;
name: string;
active: boolean = true; // 기본값
// 생성자
constructor(id: number, name: string) {
this.id = id;
this.name = name;
}
// 메서드
greet(): string {
return `Hi, ${this.name}!`;
}
}
const u = new User(1, "준성");
u.greet(); // "Hi, 준성!"
생성자 단축 — parameter properties
// 위 코드를 한 번에 — 매개변수에 접근 제어자
class User {
active: boolean = true;
constructor(public id: number, public name: string) {}
// 자동으로 this.id = id, this.name = name 됨
}
// 더 자주 쓰는 패턴 — readonly 와 함께
class User {
constructor(
public readonly id: number,
public name: string,
private password: string,
) {}
}
일일이 this.x = x 안 써도 되니까 훨씬 짧아집니다. TS-특유의 문법으로, JS 만 쓰는 코드에서는 안 보입니다.
접근 제어자 — public·private·protected
| 제어자 | 접근 가능 위치 | 런타임 강제 |
|---|---|---|
| public (기본) | 어디서나 | — |
| private | 같은 클래스 안에서만 | 컴파일 시점만 (TS) |
| protected | 자신 + 자식 클래스 | 컴파일 시점만 (TS) |
| #field (ES2022) | 같은 클래스 안에서만 | 예 (JS 표준) |
class Account {
public balance: number = 0; // 외부 접근 OK
private secret: string = "..."; // 내부만
protected log() { ... } // 자신/자식만
// ES2022 표준 — 진짜 private (런타임 강제)
#pin: string = "1234";
}
const a = new Account();
a.balance; // OK
a.secret; // ❌ TS 컴파일 에러 (런타임에는 동작)
a.#pin; // ❌ SyntaxError (런타임 강제)
TS private 의 한계. TS 의 private 는 컴파일 시점에만 체크됩니다. 런타임에는 일반 속성 — a["secret"] 같은 우회 접근 가능. 진짜 비공개가 필요하면 ES2022 의 #field (해시 프리픽스) 를 쓰세요. 단, IE 등 옛 환경은 미지원.
상속 — extends 와 super
class Animal {
constructor(public name: string) {}
speak(): string { return "..."; }
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name); // 부모 생성자 호출 필수
}
speak(): string { // 오버라이드
return `${this.name} 짖기!`;
}
}
const d = new Dog("초코", "리트리버");
d.speak(); // "초코 짖기!"
// override 키워드 (5.0+ noImplicitOverride 권장)
class Cat extends Animal {
override speak(): string {
return `${this.name} 야옹`;
}
}
abstract — 직접 인스턴스화 못하는 베이스
abstract class Shape {
abstract area(): number; // 자식이 반드시 구현
// 공통 메서드는 그대로 가짐
describe(): string {
return `면적 ${this.area()}`;
}
}
class Circle extends Shape {
constructor(public radius: number) { super(); }
area(): number { return Math.PI * this.radius ** 2; }
}
new Shape(); // ❌ Cannot create an instance of an abstract class
new Circle(5); // OK
implements — 인터페이스를 만족하는 클래스
interface Comparable<T> {
compareTo(other: T): number;
}
class Version implements Comparable<Version> {
constructor(public major: number, public minor: number) {}
compareTo(other: Version): number {
return this.major - other.major || this.minor - other.minor;
}
}
implements 는 "이 모양을 반드시 가져야" 라는 강제. 인터페이스 자체는 런타임에 사라지므로 부하 0. 여러 인터페이스를 implements 도 가능: class X implements A, B, C.
readonly · getter/setter
class Config {
readonly version: string = "1.0"; // 한 번 정해지면 변경 금지
// 정적
static readonly MAX_RETRY = 3;
// getter/setter
private _name: string = "";
get name(): string { return this._name; }
set name(v: string) {
if (!v) throw new Error("name 비울 수 없음");
this._name = v;
}
}
클래스 vs 함수 + 객체 — 언제 클래스?
실전 가이드. 다음 중 2개 이상 해당하면 클래스, 아니면 함수 + 객체:
· 상태(필드) 가 있다.
· 같은 모양의 인스턴스가 여러 개 만들어진다.
· 상속·다형성이 자연스럽다.
· implements 로 인터페이스 강제가 의미 있다.
한 가지만 해당하면 함수 + 클로저 + 객체 리터럴 조합이 더 가볍습니다.
9편 — 모듈 시스템
ESM / CJS, import·export, declaration 파일과 paths 옵션.
이전: 7편 enum · 현재: 8편 (기초) · 다음 → 9편 모듈 · 진행: 8/20