타입 별칭
우리는 객체의 모양을 정의할 때 interface를 사용하는 방법을 배웠습니다. interface는 주로 객체의 타입을 정의하고, 확장하거나 구현할 때 강력한 도구입니다. 하지만 타입스크립트에는 이 외에도 복잡한 타입을 간결하게 재사용할 수 있도록 돕는 또 다른 강력한 기능이 있는데, 바로 타입 별칭(Type Aliases)입니다.
타입 별칭은 기존에 존재하는 타입에 새로운 이름(별칭)을 부여하는 방법입니다. 이를 통해 복잡한 유니온 타입, 인터섹션 타입, 혹은 객체 리터럴 타입을 더 읽기 쉽고 관리하기 쉬운 이름으로 만들 수 있습니다. 마치 긴 주소를 짧은 별명으로 부르는 것과 같습니다.
타입 별칭 정의하기
타입 별칭에서 타입 경계, 추론 결과, 런타임 영향을 정리한 것입니다.
타입 별칭은 type 키워드를 사용하여 정의합니다.
// string 타입에 'Name'이라는 별칭을 부여합니다.
type Name = string;
let myName: Name = "김타입";
// number 타입에 'Age'라는 별칭을 부여합니다.
type Age = number;
let myAge: Age = 30;
// 유니온 타입에 별칭을 부여합니다.
type Id = string | number;
let userId: Id = "user_007";
let adminId: Id = 1004;
// 인터섹션 타입에 별칭을 부여합니다.
type Point = { x: number; y: number };
type ZCoordinate = { z: number };
type ThreeDPoint = Point & ZCoordinate;
let point3d: ThreeDPoint = { x: 10, y: 20, z: 30 };
console.log(myName); // 김타입
console.log(userId); // user_007
console.log(point3d.z); // 30위 예시에서 볼 수 있듯이, type 키워드 뒤에 별칭으로 사용할 이름을 쓰고, 등호(=) 뒤에 별칭을 부여할 타입을 정의합니다. 이렇게 정의된 별칭은 원래의 타입을 사용하는 것처럼 어디든 사용할 수 있습니다.
객체 타입 정의에 타입 별칭 사용하기
타입 별칭은 특히 객체 타입을 정의할 때 매우 유용합니다. interface와 유사하게 객체의 모양을 정의할 수 있습니다.
// 'User'라는 타입 별칭으로 객체 타입을 정의합니다.
type User = {
id: string;
name: string;
email?: string; // 선택적 속성
readonly registrationDate: Date; // 읽기 전용 속성
};
let currentUser: User = {
id: "u_abc",
name: "이코딩",
registrationDate: new Date(),
};
let newUser: User = {
id: "u_xyz",
name: "박개발",
email: "park@example.com",
registrationDate: new Date("2024-01-01"),
};
console.log(currentUser.name); // 이코딩
// newUser.registrationDate = new Date(); // Error: registrationDate는 읽기 전용입니다.이전 2장 3절에서 interface로 정의했던 Person과 거의 동일하게 User 타입을 정의했음을 알 수 있습니다.
인터페이스와 타입 별칭의 차이점
타입 별칭과 인터페이스는 객체의 타입을 정의하는 데 모두 사용될 수 있어 비슷하게 느껴질 수 있습니다. 하지만 몇 가지 중요한 차이점이 있습니다.
- 인터페이스:
extends키워드를 사용하여 다른 인터페이스를 확장할 수 있고, 클래스가implements키워드를 사용하여 인터페이스를 구현할 수 있습니다. 이는 객체 지향적인 상속과 계약 관계를 명확히 표현할 때 유리합니다. - 타입 별칭:
extends나implements키워드를 직접 사용할 수는 없습니다. 하지만 인터섹션 타입(&)을 사용하여 인터페이스와 유사한 확장 효과를 낼 수 있습니다.
// 인터페이스 확장 (extends)
interface BaseShape {
color: string;
}
interface Circle extends BaseShape {
radius: number;
}
// 타입 별칭을 이용한 '확장' (인터섹션 &)
type BaseShapeAlias = {
color: string;
};
type CircleAlias = BaseShapeAlias & {
radius: number;
};- 인터페이스: 동일한 이름으로 여러 번 선언해도 자동으로 병합(Merge)됩니다. 이는 라이브러리에서 기존 타입에 새로운 속성을 추가하는 등의 상황에서 유용합니다.
- 타입 별칭: 동일한 이름으로 여러 번 선언할 수 없습니다. 즉, 재선언 시 오류가 발생합니다.
// 인터페이스 병합 예시
interface Car {
brand: string;
}
interface Car { // 동일한 이름으로 다시 선언해도 오류 없음
model: string;
}
let myCar: Car = { brand: "BMW", model: "X5" }; // brand와 model 모두 가짐
// 타입 별칭 재선언 시 오류
// type Product = { name: string };
// type Product = { price: number }; // Error: Duplicate identifier 'Product'.- 타입 별칭: 원시 타입, 유니온, 튜플 등 모든 종류의 타입에 별칭을 부여할 수 있습니다.
- 인터페이스: 주로 객체의 모양을 정의하는 데 사용되며, 원시 타입이나 유니온, 튜플을 직접적으로 정의할 수는 없습니다. (물론 인터페이스 내부 속성으로는 가능합니다.)
type StringOrNumber = string | number; // 타입 별칭은 유니온 타입에 사용 가능
type PointTuple = [number, number]; // 타입 별칭은 튜플 타입에 사용 가능
// interface MyPrimitive extends string {} // Error: 인터페이스는 원시 타입을 확장할 수 없습니다.아래 다이어그램은 interface와 type 별칭을 선택할 때 확인할 기준을 프로젝트 적용 관점에서 정리한 것입니다.
타입 별칭과 인터페이스는 기능이 겹치는 부분이 많기 때문에 팀 규칙 없이 섞어 쓰면 읽는 사람이 의도를 추측해야 합니다. 아래 다이어그램은 새 타입을 만들 때 먼저 확인할 선택 기준을 정리한 것입니다.
언제 무엇을 사용해야 할까?
일반적인 가이드라인은 다음과 같습니다.
- 객체의 모양(Shape)을 정의하고, 향후 다른 인터페이스가 이를 확장하거나 클래스가 구현해야 할 가능성이 있다면
interface를 사용하는 것이 좋습니다. 특히 라이브러리나 프레임워크처럼 확장성이 중요한 설계에서는interface가 더 강력한 도구입니다. - 원시 타입, 유니온 타입, 튜플 타입 등 객체 이외의 타입을 포함하여 어떤 타입이든 간결하게 별칭을 부여하고 싶을 때는
type별칭을 사용합니다.interface로는 표현하기 어려운 복잡한 조합의 타입을 정의할 때 유용합니다.
최근 타입스크립트 버전에서는 interface와 type 별칭의 기능적 차이가 많이 줄어들었지만, 위에서 언급한 주요 차이점들은 여전히 유효합니다. 프로젝트의 성격과 팀의 컨벤션에 따라 선택하여 사용할 수 있습니다.
이로써 타입스크립트의 기본 타입들에 대한 학습을 마쳤습니다. 숫자, 문자열, 불리언과 같은 기본 데이터부터 시작하여, 복잡한 객체와 그 형태를 정의하는 인터페이스, 그리고 유연한 타입 조합을 위한 유니온/인터섹션, 마지막으로 타입에 새 이름을 부여하는 타입 별칭까지, 타입스크립트의 견고한 타입 시스템을 위한 핵심 개념들을 살펴보았습니다.
다음 다이어그램은 TypeScript 타입 별칭을 객체, 유니온, 함수 시그니처, 재사용 경계로 나누어 쓰는 기준입니다.
다음 다이어그램은 타입 별칭을 언제 쓰고 interface와 어떻게 나눌지 정리한 판단표입니다.
타입 별칭에서는 타입 경계, 추론 범위, 호출부 영향이 어디에서 달라지는지 마지막으로 점검합니다.
아래 다이어그램은 type 별칭과 interface를 언제 선택할지 확장성과 표현 범위로 비교합니다.