Typescript - 클래스

Stella·2026년 1월 10일

TypeScript

목록 보기
4/4

클래스

Typescript에서 클래스 기능은 c#에서 유래된 것이 많다.
컴파일 후에 사라진다.

항상 대문자로 시작
class PersonContext {
name: string = "";
age: number = 0;
readonly location: string = "Korea"; // readonly 수정 불가능하게 한다.

생성자

초기화를 담당한다. -> 수정 가능하다.
constructor(name: string, age: number) { 인스턴스를 셋팅하고 초기화한다.
this.name = name // this가 생성될 인스턴스를 바라본다.
this.age = age
}
}

const p1 = new PersonContext(‘Jang’, 99); // 인스턴스
Const p2 = new PersonContext(‘Poco’, 100);

인스턴스 = 실제 건물 (유연한 결합)

클래스에서 파생된 고유한 것 실제로 생성된 후 메모리에 올라간다.
설계도를 보고 실제로 벽돌을 쌓아 올린 실제 건물이다.
처음부터 끝까지 직접 코드를 짠다. 여러 개를 동시에 가져다 쓸 수 있다.

메서드

객체(클래스)에서는 행동을 뜻한다.
함수이기도 하다. 클래스가 가지고 있는 함수
introduce(): string {
return ${this.name}의 나이는 ${this.age}입니다.
}
console.log(p1.introduce())

Getter, setter

필드의 접근할 권한을 가진 제어자이다. (외부에서 값이 어떻게 바뀌는지 통제 가능)
getter O / setter X => 속성은 자동으로 읽기 전용
setter 매개변수의 타입 X / getter의 반환 타입에서 추론
private 속성은 .연산자로 접근할 수 없다.

객체에 속성에 접근할 때 실행되는 함수이다.
get : 값을 읽을 때 실행
set : 값을 쓸 때 실행

class Person {
	name: string;
    private _age: number;
    
    constructor(name: string, age: number) {
    	this.name = name
        this._age = age
    }
    get age() {
    	if (this._age === 0) {
        	return '설정되지 않았습니다.'
        }
    	return `나이는 ${this._age}세로 추정됩니다.`
    }
    
    set age(age) {
    	if (typeof age === 'number') {
        	this._age = age	
    	}
        this._age = 0;
}

const p = new Person('Jang' 99); // p가 인스턴스이다. 메모리 어딘가에 값을 담고 메서드를 실행할 수 있는 실체가 생겨난 것이다.
console.log(p.age)
console.log(p.name)

extends (상속)

상속, 확장

class 기본 {
	result() {
    	return 'Base'
    }
}

class 파생 extends 기본 {
	result() {
    	return 'Derived'
    }
}

const de = new 파생()
console.log(de.result()) // "Drived"

super

super는 상속받은 부모 클래스를 의미해.
super() → 부모 클래스의 생성자 호출
super.method() → 부모 클래스의 메서드 호출

class Animal {
  name: string;

  constructor(name: string) {
    this.name = name;
  }
}

class Dog extends Animal {
  breed: string;

  constructor(name: string, breed: string) {
    super(name);          // ✅ 부모 생성자 호출 (필수)
    this.breed = breed;
  }
}

const dog = new Dog("Buddy", "Poodle");

접근 제어자

public : 기본값, 어디서든 자유롭게 접근 가능
protected : 해당 클래스와 이를 상속받은 자식 클래스에서만 접근 가능하다.
private : 해당 클래스 내부에서만 접근 가능하다.

class Account {
  public bankName: string = "Hana Bank"; // 누구나 접근 가능
  protected owner: string;              // 자신과 자식 클래스만 가능
  private balance: number;               // 오직 이 클래스 내부에서만

  constructor(owner: string, initialBalance: number) {
    this.owner = owner;
    this.balance = initialBalance;
  }

  public showBalance() {
    console.log(`잔액은 ${this.balance}원입니다.`); // 클래스 내부이므로 접근 가능
  }
}

const myAccount = new Account("Stella", 10000);
console.log(myAccount.bankName); // OK
// console.log(myAccount.balance); // Error: private이라서 외부 접근 불가

static

인스턴스가 아닌, 클래스 자체에 귀속되는 속성이나 메서드이다.
인스턴스 생성하지 않고도 클래스 이름을 통해 바로 호출할 수 있다. 공유해야 하는 고정된 값이나 유틸리티 함수에 사용한다.

class Circle {
  static PI: number = 3.14159; // 모든 원이 공유하는 고정값

  static calculateArea(radius: number) {
    return this.PI * radius * radius;
  }
}

console.log(Circle.PI); // 인스턴스 없이 바로 접근
console.log(Circle.calculateArea(5));

readonly

값을 수정할 수 없게 만드는 제어자이다.

class Person {
  public readonly birthDate: string;

  constructor(date: string) {
    this.birthDate = date; // 초기 할당 가능
  }

  updateBirth() {
    // this.birthDate = "2000-01-01"; // Error: 읽기 전용 속성이라 수정 불가
  }
}

추상 클래스 abstract = 인스턴스 생성 불가능, 파생으로 가능

abstract를 선언한 클래스로 직접 인스턴스를 생성 불가능하다.
직접 인스턴스화 될 수 없지만 extends후 파생된 클래스를 인스턴스화하도록 유도한다.
추상 클래스는 구현된 메서드를 포함시킬 수 있다.
abstract 선언한 메서드는 파생된 클래스에서 메서드를 구현해야 한다.

= 자식 클래스들이 공통으로 가져야 할 변수나 로직이 있다면 추상 클래스가 훨씬 유리하다.
전체적인 실행 흐름은 같은데, 특정 단계만 다를 때 사용한다.

abstract class GameCharacter {
  constructor(protected hp: number) {}

  // 모든 캐릭터가 공통으로 사용하는 로직
  takeDamage(amount: number) {
    this.hp -= amount;
    console.log(`남은 체력: ${this.hp}`);
  }

  // 공격 방식은 캐릭터마다 다름
  abstract attack(): void;
}
abstract class Animal {
	// 선언된 메서드
    abstract hello(str: string): string {
    
    }
    // 구현된 메서드
    run() {
    	return this.hello() + 'run'
    }
}
// abstract를 붙이면 직접 인스턴스화가 될 수 없다.
const animal = new Animal() 

class Person extends Animal {
// 파생된 클래스는 가능하다.
	hello() {
    	return 'Person'
    }
}
const person = new Person()  
console.log(person.hello()) // "Person"정상적으로 실행될 수 있다.

Parameter Properties = 매개변수를 받는다.

typescript에서 필드를 생성하고, 생성자 매개변수를 동일하게 만드는 과정이 귀찮을 때
접근제어자, 생성자 필드 네임, 타입을 생성자 매개변수를 받는 방법

= 매개변수에 다 넣고 this도 생략한다.

class Person {
	constructor(public name: string, private age: number, protected gender: 'M' | 'F') { // 매개변수에 넣을 수 있다.
    //this.name = name 
    //this.age = age
    //this.gender = gender
    = this도 생략이 가능하다.
  	}
    
    sayName() { 
    	return `이름은 ${this.name} 입니다.`
    }
    
    protected sayAge() {
    	return `나이는 ${this.age}`
        }
    }
    
    

메서드 오버라이딩

부모 클래스에서 물려받은 메서드를 자신의 용도에 맞게 재정의 하는것이다.
클래스로 만든것을 확장하더라도 오버라이딩 할 수 있다.

1) extends 사용

class Animal {
	run() {
    	return 'Animal이 달리다'
    }
}
class Dog extends Animal {
	run() {
    	return 'Dog이 달리다'
    }
}
class Person extends Animal {
	run() {
    	return 'Person이 달리다'
    }
}

const p = new Person()
const d = new Dog()

console.log(p.run()) // Animal이 달리다
console.log(d.run())

2) super 키워드 활용
부모의 기능을 완전히 버리는 것이 아니라, 부모의 기능을 먼저 수행하고, 추가적인 로직을 더하고 싶을 때 super을 사용한다.

class Robot {
  work() {
    console.log("시스템 가동...");
  }
}

class CleaningRobot extends Robot {
  work() {
    super.work(); // 부모의 work() 실행 ("시스템 가동...")
    console.log("청소를 시작합니다."); // 자식만의 추가 로직
  }
}

오버라이딩 vs 오버로딩

  • 오버라이딩 : 상속 관계에서 부모의 메서드를 자신의 입맛에 맞게 재정의한다.
    부모의 기능을 무시하거나(덮어쓰기)extends, super를 통해 부모의 기능을 포함하여 확장한다.

  • 오버로딩 : 같은 이름의 메서드를 매개변수만 다르게 여러 방식으로 호출할 수 있게 하는 것이다.
    (여러 옵션 쌓기), 매개 변수가 달라야 한다. 다양한 입력 타입에 유연하게 대응한다.

// 1. 오버로드 시그니처 (함수 선언부)
function add(a: string, b: string): string;
function add(a: number, b: number): number;

// 2. 함수 구현부 (실제 로직)
function add(a: any, b: any): any {
  return a + b;
}

console.log(add(10, 20));      // 30 (number 타입으로 작동)
console.log(add("안녕", "세상")); // "안녕세상" (string 타입으로 작동)
// console.log(add(10, "안녕")); // Error: 선언부에 없는 조합은 사용 불가
profile
공부 기록

0개의 댓글