Adventure Time - Finn 3
본문 바로가기
프론트

TypeScript 클래스(Class)

by hyun9_9 2026. 4. 11.

JavaScript 클래스와의 차이점부터 접근 제한자, static, 추상 클래스까지 단계별로 정리합니다.


1. JS 클래스와 TS 클래스의 차이

JavaScript에서는 constructor에서 바로 this.color를 할당해도 문제가 없습니다. 하지만 TypeScript에서는 멤버 변수를 먼저 선언해야 합니다.

// ❌ TypeScript에서는 에러
class Car {
  constructor(color) {
    this.color = color;  // color가 선언되지 않음
  }
}

// ✅ 멤버 변수를 먼저 선언
class Car1 {
  color: string;
  constructor(color: string) {
    this.color = color;
  }
  start() {
    console.log("start");
  }
}

const bmw1 = new Car1("red");

멤버 변수 선언 생략하는 방법

constructor 매개변수에 접근 제한자(public, private, protected)나 readonly를 붙이면 멤버 변수 선언을 생략할 수 있습니다.

class Car2 {
  constructor(public color: string) {
    this.color = color;
  }
  start() {
    console.log("start");
  }
}

const bmw3 = new Car2("red");

💡 public color: string이 매개변수 선언과 멤버 변수 선언을 동시에 처리해줍니다. 코드를 간결하게 유지할 수 있는 TypeScript만의 편의 문법입니다.


2. 접근 제한자 (Access Modifier)

클래스 내부의 프로퍼티와 메서드에 접근할 수 있는 범위를 제어합니다.

public (기본값)

어디서든 접근 가능합니다. 아무것도 표시하지 않으면 자동으로 public입니다.

private (또는 #)

해당 클래스 내부에서만 접근 가능합니다. 자식 클래스에서도 사용할 수 없습니다.

class Car3 {
  private name: string = "car";
  color: string;
  constructor(color: string) {
    this.color = color;
  }
  start() {
    console.log("start");
    console.log(this.name);  // ✅ OK — 같은 클래스 내부
  }
}

class Bmw3 extends Car3 {
  constructor(color: string) {
    super(color);
  }
  showName() {
    console.log(super.name);  // ❌ Error — private은 자식에서 접근 불가
  }
}

protected

자식 클래스 내부에서는 접근 가능하지만, 클래스 인스턴스에서는 접근할 수 없습니다.

class Car {
  protected name: string = "car";
}

class Bmw extends Car {
  showName() {
    console.log(this.name);  // ✅ OK — 자식 클래스 내부
  }
}

const z4 = new Bmw();
z4.name;  // ❌ Error — 인스턴스에서 접근 불가

정리

접근 제한자 클래스 내부 자식 클래스 인스턴스

public
protected
private / #

3. readonly

readonly를 붙이면 값을 읽을 수만 있고 수정할 수 없습니다. 단, constructor 내부에서는 초기값을 할당할 수 있습니다.

class Car4 {
  readonly name: string = "car";
  color: string;
  constructor(color: string, name: string) {
    this.color = color;
    this.name = name;  // ✅ OK — constructor 내부에서는 할당 가능
  }
}

const z5 = new Car4("red", "zzz");
z5.name = "aaa";  // ❌ Error — 읽기전용 프로퍼티는 수정 불가

💡 readonly는 "생성 시 한 번만 값을 정하고, 이후로는 변경하지 않겠다"는 의도를 명확히 표현합니다.


4. static (정적 멤버)

static으로 선언한 프로퍼티나 메서드는 인스턴스가 아닌 클래스 자체에 속합니다. 접근할 때 this가 아닌 클래스 이름을 사용해야 합니다.

class Car4 {
  readonly name: string = "car";
  color: string;
  static wheels = 4;
  constructor(color: string, name: string) {
    this.color = color;
    this.name = name;
  }
  start() {
    console.log("start");
    console.log(this.wheels);  // ❌ Error — this로 접근 불가
    console.log(Car4.wheels);  // ✅ OK — 클래스 이름으로 접근
  }
}

console.log(Car4.wheels);  // 4

⚠️ static 멤버는 인스턴스마다 생성되지 않고 클래스에 하나만 존재합니다. 모든 인스턴스가 공유하는 값(바퀴 수, 설정값 등)에 적합합니다.


5. 추상 클래스 (Abstract Class)

abstract 키워드를 붙인 클래스는 직접 인스턴스를 만들 수 없고, 반드시 상속을 통해서만 사용합니다.

abstract class Car5 {
  readonly name: string = "car";
  color: string;
  constructor(color: string) {
    this.color = color;
  }
  start() {
    console.log("start");
  }
  abstract doSome(): void;  // 추상 메서드 — 구현부 없음
}

const car = new Car5("red");  // ❌ Error — 추상 클래스는 new로 생성 불가

추상 메서드 구현

추상 클래스 안의 추상 메서드는 상속받은 자식 클래스에서 반드시 구현해야 합니다.

class Bmw5 extends Car5 {
  constructor(color: string) {
    super(color);
  }
  doSome() {
    console.log("Bmw만의 동작");
  }
}

const myBmw = new Bmw5("blue");
myBmw.start();   // "start" — 부모에서 상속
myBmw.doSome();  // "Bmw만의 동작" — 자식에서 구현

💡 추상 클래스는 공통 구조는 정의하되, 세부 동작은 자식에게 위임하는 패턴입니다. start()처럼 공통 로직은 부모에 구현하고, doSome()처럼 자식마다 달라지는 로직은 추상 메서드로 선언합니다.


한눈에 보기

기능 문법 설명

멤버 변수 선언 color: string; TS에서는 반드시 선언 필요
매개변수 축약 constructor(public color: string) 선언과 할당을 동시에
public 기본값 어디서든 접근 가능
protected protected name 자식 클래스까지만 접근
private private name / #name 해당 클래스 내부만 접근
readonly readonly name 수정 불가 (constructor 제외)
static static wheels = 4 클래스 자체에 속하는 멤버
추상 클래스 abstract class Car 직접 생성 불가, 상속 전용
추상 메서드 abstract doSome(): void 자식에서 반드시 구현