TypeScript
TypeScript : 객체 지향 프로그래밍 - 1 (Class, 상속)
고래고래00
2024. 7. 2. 20:03
01. 클래스
- 클래스는 객체 지향 프로그래밍(OOP)의 핵심 구성 요소 중 하나
- 클래스는 객체를 만들기 위한 틀(template)
클래스의 구성 요소
- 클래스에서는 같은 종류의 객체들이 공통으로 가지는 속성(attribute)과 메서드(method)를 정의
- 속성은 객체의 성질을 결정
- 메서드는 객체의 성질을 변화시키거나 객체에서 제공하는 기능들을 사용하는 창구
객체란?
- 객체는 클래스를 기반으로 생성되며 클래스의 인스턴스(instance)라고도 함
클래스 및 객체 정의 방법
- TypeScript에서 클래스를 정의하려면 class 키워드 사용
- 클래스의 속성과 메서드를 정의하고, new 키워드 사용하여 객체를 생성
더보기
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`안녕하세요! 제 이름은 ${this.name}이고, 나이는 ${this.age}살입니다.`);
}
}
const person = new Person('Spartan', 30);
person.sayHello();
- 생성자(constructor)
- 생성자는 클래스의 인스턴스를 생성하고 초기화하는데 사용되는 메서드
- 생성자는 클래스 내에서 constructor라는 이름으로 정의
- 생성자는 인스턴스를 생성할 때 자동으로 호출
- 생성자는 클래스 내에 오직 하나만 존재할 수 있음
- 보통, 생성자로 객체 속성을 초기화 하는것 뿐 아니라 객체가 생성이 될 떄 꼭 되어야 하는 초기화 로직을 집어넣기도 함
- 예를 들어, DBConnector라는 클래스가 있다면 이 클래스 타입의 객체가 생성이 될 때 생성자에서 DB 연결을 미리 해주면 편할 것
접근 제한자
- 클래스에서는 속성과 메서드에 접근 제한자를 사용해 접근을 제한
- TypeScript에서는 다음의 접근 제한자들 제공
- public
- 클래스 외부에서도 접근이 가능한 접근 제한자
- 접근 제한자가 선언이 안되어있다면 기본적으로 접근 제한자는 public
- 클래스의 함수 중 민감하지 않은 객체 정보를 열람할 때나 누구나 해당 클래스의 특정 기능을 사용해야 할 때 사용
- private
- 클래스 내부에서만 접근이 가능한 접근 제한자
- 보통은 클래스의 속성은 대부분 private으로 접근 제한자를 설정
- 즉, 외부에서 직접적으로 객체의 속성을 변경할 수 없게 제한
- 클래스의 속성을 보거나 편집하고 싶다면 별도의 getter/setter 메서드를 준비해놓는 것이 관례
- protected
- 클래스 내부와 해당 클래스를 상속받은 자식 클래스에서만 접근이 가능한 접근 제한자
- public
더보기
class Person {
private name: string;
private age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
public sayHello() {
console.log(`안녕하세요! 제 이름은 ${this.name}이고, 나이는 ${this.age}살입니다.`);
}
}
02. 상속
상속(inheritance)
- 상속은 객체 지향 프로그래밍에서 클래스 간의 관계를 정의하는 중요한 개념
- 상속을 통해 기존 클래스의 속성과 메서드를 물려받아 새로운 클래스를 정의
- 상속이 있어서 똑같은 코드를 계속 반복적으로 작성할 필요 X
- 상속을 구현하려면 extends 키워드
더보기
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound() {
console.log('동물 소리~');
}
}
class Dog extends Animal {
age: number;
constructor(name: string) {
super(name);
this.age = 5;
}
makeSound() {
console.log('멍멍!'); // 부모의 makeSound 동작과 다름
}
eat() { // Dog 클래스만의 새로운 함수 정의
console.log('강아지가 사료를 먹습니다.');
}
}
class Cat extends Animal { // Animal과 동일
}
const dog = new Dog('누렁이');
dog.makeSound(); // 출력: 멍멍!
const cat = new Cat('야옹이');
cat.makeSound(); // 출력: 동물 소리~
- 여기서 Animal을 부모 클래스, Dog를 자식 클래스
- super 키워드는 자식 클래스가 부모 클래스를 참조하는데 사용하는 키워드
- 즉, 자식 클래스에서 생성자를 정의할 때 부모 클래스의 생성자를 호출해야 할 때 사용
서브타입과 슈퍼타입
더보기
서브타입
- 두 개의 타입 A와 B가 있고 B가 A의 서브타입이면 A가 필요한 곳에는 어디든 B를 안전하게 사용할 수 있다.
슈퍼타입
- 두 개의 타입 A와 B가 있고 B가 A의 슈퍼타입이면 B가 필요한 곳에는 어디든 A를 안전하게 사용할 수 있다.
- any는 모든 것의 슈퍼타입
- Animal은 Dog, Cat의 슈퍼타입이고요. Dog, Cat은 Animal의 서브타입
upcasting
let dog: Dog = new Dog('또순이');
let animal: Animal = dog; // upcasting
animal.eat(); // 에러. 슈퍼타입(Animal)으로 변환이 되어 eat 메서드를 호출 불가
- 서브타입 → 슈퍼타입으로 변환을 하는 것을 upcasting
- 이 경우에는 타입 변환은 암시적으로 이루어져 별도의 타입 변환 구문이 필요 X
- TypeScript가 자동으로 해줌
- 위의 코드에서도 단지 슈퍼타입 변수에 대입
- upcasting의 필요성 : 서브타입 객체를 슈퍼타입 객체로 다루면 유연하게 활용 가능
- 예를 들어, Dog, Cat, Lion 그리고 기타 등등 다양한 동물을 인자로 받을 수 있는 함수?
- Animal 타입의 객체를 받으면 모두 다 받을 수 있음 O
- union으로 새로운 타입을 만들어서 해당 타입의 객체를 받게 함 X
- 예를 들어, Dog, Cat, Lion 그리고 기타 등등 다양한 동물을 인자로 받을 수 있는 함수?
downcasting
let animal: Animal;
animal = new Dog('또순이');
let realDog: Dog = animal as Dog;
realDog.eat(); // 서브타입(Dog)로 변환이 되었기 때문에 eat 메서드를 호출 가능
- 슈퍼타입 → 서브타입으로 변환을 하는 것을 downcasting
- 이 경우에는 as 키워드로 명시적으로 타입 변환
- downcasting의 필요성 : Dog와 같은 서브타입의 메서드를 사용해야 될 때