TypeScriptTypeScript 기초강의 8개 중 5번째난이도 기초

클래스와 접근 제어자 — TypeScript OOP

발행 읽는 시간 약 1 분

  • TypeScript
  • 클래스
  • OOP
  • 접근제어자
  • 추상클래스

강의 소개

TypeScript 클래스의 접근 제어자(public, private, protected), 추상 클래스, 인터페이스 구현을 배웁니다. JavaScript 클래스와의 차이도 이해합니다.

TypeScript 클래스 기초#

TypeScript
class User {
    // 속성 선언 (TypeScript 필수)
    id: number;
    name: string;
    private email: string;      // private: 클래스 내부만 접근
    protected role: string;     // protected: 상속 클래스까지
    readonly createdAt: Date;   // readonly: 재할당 불가

    constructor(id: number, name: string, email: string) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.role = "user";
        this.createdAt = new Date();
    }

    getEmail(): string {
        return this.email;  // private이지만 클래스 내부에서 접근 가능
    }
}

const user = new User(1, "철수", "kim@example.com");
console.log(user.name);        // ✅
// console.log(user.email);    // ❌ private

생성자 단축 문법#

TypeScript
// 반복적인 this.xxx = xxx를 줄이는 방법
class User {
    readonly createdAt: Date = new Date();

    constructor(
        public id: number,
        public name: string,
        private email: string,
        protected role: string = "user",
    ) {}

    getEmail() { return this.email; }
}

접근 제어자 비교#

Diagram · Mermaid

상속#

TypeScript
class AdminUser extends User {
    constructor(
        id: number,
        name: string,
        email: string,
        private permissions: string[],
    ) {
        super(id, name, email);  // 부모 생성자 호출
        this.role = "admin";    // protected이므로 접근 가능
    }

    hasPermission(perm: string): boolean {
        return this.permissions.includes(perm);
    }
}

const admin = new AdminUser(2, "관리자", "admin@example.com", ["delete", "edit"]);
console.log(admin.hasPermission("delete"));  // true

인터페이스 구현#

TypeScript
interface Serializable {
    serialize(): string;
    deserialize(data: string): void;
}

interface Loggable {
    log(): void;
}

class Document implements Serializable, Loggable {
    constructor(
        public title: string,
        public content: string,
    ) {}

    serialize(): string {
        return JSON.stringify({ title: this.title, content: this.content });
    }

    deserialize(data: string): void {
        const parsed = JSON.parse(data);
        this.title = parsed.title;
        this.content = parsed.content;
    }

    log(): void {
        console.log(`[Document] ${this.title}`);
    }
}

추상 클래스#

인스턴스를 직접 만들 수 없고, 반드시 상속해서 사용합니다.

TypeScript
abstract class Shape {
    abstract getArea(): number;    // 반드시 구현해야 함
    abstract getPerimeter(): number;

    // 구현된 메서드는 상속됨
    describe(): string {
        return `넓이: ${this.getArea()}, 둘레: ${this.getPerimeter()}`;
    }
}

class Circle extends Shape {
    constructor(private radius: number) {
        super();
    }

    getArea(): number {
        return Math.PI * this.radius ** 2;
    }

    getPerimeter(): number {
        return 2 * Math.PI * this.radius;
    }
}

// const shape = new Shape();  // ❌ 추상 클래스 직접 인스턴스화 불가
const circle = new Circle(5);
console.log(circle.describe());

static 멤버#

TypeScript
class Counter {
    private static count = 0;

    static increment(): void {
        Counter.count++;
    }

    static getCount(): number {
        return Counter.count;
    }
}

Counter.increment();
Counter.increment();
console.log(Counter.getCount());  // 2

실전: 제네릭 Repository 패턴#

TypeScript
interface Entity {
    id: number;
}

abstract class Repository<T extends Entity> {
    protected items: T[] = [];

    findById(id: number): T | undefined {
        return this.items.find(item => item.id === id);
    }

    save(item: T): void {
        const index = this.items.findIndex(i => i.id === item.id);
        if (index >= 0) {
            this.items[index] = item;
        } else {
            this.items.push(item);
        }
    }

    findAll(): T[] {
        return [...this.items];
    }

    abstract validate(item: T): boolean;
}

class UserRepository extends Repository<User> {
    validate(user: User): boolean {
        return user.name.length > 0;
    }
}

정리#

제어자접근 범위
public어디서든
private클래스 내부만
protected클래스 + 상속 클래스
readonly재할당 불가
static인스턴스 없이 접근
abstract구현 강제

다음 편에서는 유틸리티 타입 — Partial, Required, Readonly, Pick, Omit 등 내장 타입 변환 도구를 배웁니다.

Follow · Ask · Work

이 글이 도움이 됐다면

짧은 작업 기록과 데모는 인스타그램에 올립니다. 만들고 싶은 것이 있다면 프로젝트 의뢰나 협업 제안도 편하게 보내 주세요.

글쓴이

파란여우

직접 만든 AI 앱·제품의 개발·배포를 공개하는 실전형 테크 크리에이터

파란여우 소개 Instagram @bluefox._.hi

이어서 보기

만들고 싶은 것이 있다면 프로젝트 의뢰로 알려 주세요.