안녕하세요, 오늘은 TypeScript의 핵심 개념 중 하나인 타입 추론, 타입 단언, 그리고 클래스에 대해 자세히 알아보겠습니다. TypeScript는 자바스크립트에 정적 타입을 도입하여 코드의 안정성과 가독성을 높여주는 강력한 도구입니다. 이 글에서는 이러한 기능들이 어떻게 작동하는지, 그리고 실제 프로젝트에서 어떻게 활용할 수 있는지 예제와 함께 설명드리겠습니다.
타입 추론은 TypeScript 컴파일러가 변수의 타입을 명시적으로 선언하지 않아도, 코드의 문맥을 통해 타입을 유추하는 기능입니다. 이를 통해 개발자는 코드의 간결성을 유지하면서도 타입의 이점을 누릴 수 있습니다.
let message = 'Hello, TypeScript!';
// TypeScript는 'message' 변수를 자동으로 'string' 타입으로 추론합니다.
message = 'Another message'; // 정상적으로 작동
// message = 42; // 오류: number 타입을 할당할 수 없습니다.
위 예제에서 message
변수는 초기값으로 문자열을 할당받았기 때문에 TypeScript는 이를 string
타입으로 추론합니다. 이후 message
에 다른 문자열을 할당하는 것은 문제가 없지만, 숫자를 할당하려고 하면 컴파일 오류가 발생합니다.
function add(a: number, b: number) {
return a + b;
}
// TypeScript는 'add' 함수의 반환 타입을 'number'로 추론합니다.
const result = add(5, 10); // result는 'number' 타입
함수의 경우, 반환되는 값의 타입을 기반으로 반환 타입이 자동으로 결정됩니다. 이는 함수의 사용을 더욱 편리하게 만들어줍니다.
타입 단언은 개발자가 컴파일러에게 특정 변수의 타입을 "확신"시켜주는 방법입니다. 이는 컴파일러가 변수의 타입을 정확히 추론하지 못할 때 유용하게 사용됩니다. 타입 단언은 두 가지 방식으로 사용할 수 있습니다: as
구문과 <>
구문.
let someValue: any = 'Hello, TypeScript!';
// 'as' 구문을 사용한 타입 단언
let strLength = (someValue as string).length;
console.log('Length(as 구문):', strLength); // 출력: Length(as 구문): 16
// '<>' 구문을 사용한 타입 단언
let strLengthAlt = (<string>someValue).length;
console.log('Length(<>) 구문:', strLengthAlt); // 출력: Length(<> 구문): 16
위 예제에서 someValue
는 any
타입으로 선언되어 있어, TypeScript는 해당 변수의 타입을 알 수 없습니다. 이때 타입 단언을 사용하여 someValue
가 string
타입임을 명시하면, 문자열의 길이를 안전하게 구할 수 있습니다.
타입 단언은 컴파일러에게 타입 정보를 제공하는 것이지만, 실제 런타임에서는 아무런 영향을 미치지 않습니다. 따라서 잘못된 타입 단언은 런타임 오류를 발생시킬 수 있으므로, 타입 단언을 사용할 때는 변수의 실제 타입을 정확히 알고 있어야 합니다.
클래스는 객체 지향 프로그래밍의 기본 단위로, 데이터와 해당 데이터를 조작하는 메서드를 하나의 구조로 묶어줍니다. TypeScript는 ES6의 클래스를 기반으로 다양한 기능을 추가하여 더욱 강력한 클래스 시스템을 제공합니다.
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet() {
console.log(`안녕하세요, 저는 ${this.name}이고 ${this.age}살입니다.`);
}
}
const person1 = new Person('홍길동', 30);
person1.greet(); // 출력: 안녕하세요, 저는 홍길동이고 30살입니다.
위 예제에서 Person
클래스는 name
과 age
라는 두 개의 속성과 greet
라는 메서드를 가지고 있습니다. 생성자를 통해 초기값을 설정하고, greet
메서드를 통해 인사말을 출력합니다.
TypeScript는 클래스의 멤버에 접근 제한자를 사용할 수 있습니다: public
, private
, protected
.
class Animal {
public name: string;
private species: string;
protected age: number;
constructor(name: string, species: string, age: number) {
this.name = name;
this.species = species;
this.age = age;
}
public getSpecies(): string {
return this.species;
}
}
const animal = new Animal('Leo', '사자', 5);
console.log(animal.name); // 정상 접근: 'Leo'
// console.log(animal.species); // 오류: 'species'는 private입니다.
// console.log(animal.age); // 오류: 'age'는 protected입니다.
console.log(animal.getSpecies()); // 정상 접근: '사자'
public
: 모든 곳에서 접근 가능합니다. 기본 접근 제한자입니다.private
: 클래스 내부에서만 접근 가능합니다.protected
: 클래스 내부와 상속받은 클래스에서 접근 가능합니다.클래스는 상속을 통해 기존 클래스를 확장할 수 있습니다.
class Employee extends Person {
private employeeId: number;
constructor(name: string, age: number, employeeId: number) {
super(name, age);
this.employeeId = employeeId;
}
public getEmployeeInfo() {
console.log(`직원 ID: ${this.employeeId}`);
}
}
const employee = new Employee('김철수', 28, 1001);
employee.greet(); // 출력: 안녕하세요, 저는 김철수이고 28살입니다.
employee.getEmployeeInfo(); // 출력: 직원 ID: 1001
Employee
클래스는 Person
클래스를 상속받아 employeeId
라는 새로운 속성과 getEmployeeInfo
라는 메서드를 추가하였습니다. super
키워드를 사용하여 부모 클래스의 생성자를 호출할 수 있습니다.
TypeScript는 클래스에서도 제네릭을 사용할 수 있습니다. 이를 통해 다양한 타입에 대응하는 유연한 클래스를 만들 수 있습니다.
interface DataItem<T> {
id: number;
value: T;
}
class DataManager<T> {
private items: DataItem<T>[] = [];
addItem(item: DataItem<T>): void {
this.items.push(item);
}
removeItem(id: number): void {
this.items = this.items.filter(item => item.id !== id);
}
getItems(): DataItem<T>[] {
return this.items;
}
}
// 문자열 데이터를 관리하는 인스턴스
const stringManager = new DataManager<string>();
stringManager.addItem({ id: 1, value: '첫 번째 문자열' });
stringManager.addItem({ id: 2, value: '두 번째 문자열' });
console.log('문자열 아이템:', stringManager.getItems());
// 숫자 데이터를 관리하는 인스턴스
const numberManager = new DataManager<number>();
numberManager.addItem({ id: 1, value: 100 });
numberManager.addItem({ id: 2, value: 200 });
console.log('숫자 아이템:', numberManager.getItems());
위 예제에서 DataManager
클래스는 제네릭을 사용하여 다양한 타입의 데이터를 관리할 수 있습니다. stringManager
와 numberManager
는 각각 문자열과 숫자 데이터를 관리하는 인스턴스입니다.
오늘은 TypeScript의 타입 추론, 타입 단언, 그리고 클래스에 대해 알아보았습니다. TypeScript는 이러한 기능들을 통해 자바스크립트의 유연성과 함께 정적 타입의 안정성을 제공합니다.
TypeScript를 활용하여 더욱 견고하고 효율적인 코드를 작성해 보세요! 앞으로도 유용한 TypeScript 관련 내용으로 찾아뵙겠습니다. 감사합니다!