타입 별칭
복잡한 유니온·인터섹션·객체 타입에 재사용 가능한 이름을 붙이고 확장 방식에 따라 type과 interface를 선택합니다.
우리는 객체의 모양을 정의할 때 interface를 사용하는 방법을 배웠습니다.
interface는 주로 객체의 타입을 정의하고, 확장하거나 구현할 때 강력한 도구입니다.
하지만 타입스크립트에는 이 외에도 복잡한 타입을 간결하게 재사용할 수 있도록 돕는 또 다른 강력한 기능이 있는데, 바로 타입 별칭(Type Aliases)입니다.
타입 별칭은 기존에 존재하는 타입에 새로운 이름(별칭)을 부여하는 방법입니다.
이를 통해 복잡한 유니온 타입, 인터섹션 타입, 혹은 객체 리터럴 타입을 더 읽기 쉽고 관리하기 쉬운 이름으로 만들 수 있습니다.
마치 긴 주소를 짧은 별명으로 부르는 것과 같습니다.
TYPE / RUNTIME / CONTRACT
타입 별칭은 기존 계약에 이름을 붙인다
Name=string, Id=string|number, ThreeDPoint=Point&ZCoordinate처럼 타입 식을 재사용합니다. 별칭의 다른 이름만으로 값이 분리되거나 런타임 객체가 만들어지지는 않습니다.
ACTUAL ALIASES
Name · Age · Id에 읽기 쉬운 이름
Name=string,Age=number,Id=string|number입니다. 별칭을 붙여도 기존 허용 값과 연산은 그대로입니다. 이름이 다르다는 이유만으로 같은 string ID가 서로 구별되지는 않습니다.
ACTUAL INTERSECTION
ThreeDPoint는 x · y · z를 요구
Point의x/y와 ZCoordinate의z를 결합하고 실제 객체는10/20/30을 제공합니다. 타입 별칭이 누락된 z 값을 자동으로 채워 주지 않습니다.
ACTUAL OBJECT ALIAS
User의 선택·읽기 전용 속성
User.email은 생략할 수 있고 registrationDate의 재할당은 readonly로 제한합니다. Date 객체 내부를 동결하는 계약은 아닙니다.
ERASURE / ADDITIONAL DESIGN
검증이나 별도 의미 구분은 직접 설계
type 선언은 JavaScript에 남지 않습니다. 외부 값을 확인하는 validator나 의미가 다른 ID를 구분하는 brand는 별도로 설계하며, 이 절의 alias 예제에는 구현되어 있지 않습니다.
type은 기존 타입 식에 재사용할 이름을 붙입니다. Name·Age·Id·ThreeDPoint의 계약을 확인하며 별칭이 런타임 wrapper나 validator를 생성하지 않음을 구분합니다.
타입 별칭 정의하기
타입 별칭은 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 키워드 뒤에 별칭으로 사용할 이름을 쓰고, 등호(=) 뒤에 별칭을 부여할 타입을 정의합니다.
이렇게 정의된 별칭은 원래의 타입을 사용하는 것처럼 어디든 사용할 수 있습니다.
별칭은 서로 다른 런타임 값의 종류를 새로 만드는 기능이 아닙니다. 이름이 다른 두 별칭이 모두 number라면 서로 할당할 수 있습니다.
예시
type Meters = number;
type Seconds = number;
const duration: Seconds = 5;
const distance: Meters = duration; // 타입 검사는 허용합니다.
console.log(distance); // 5이 코드는 초를 미터로 변환하지 않습니다. 이름은 사람이 의도를 읽는 데 도움이 되지만 단위가 다른 값을 자동으로 차단하지는 않습니다. User처럼 객체 구조에 붙인 별칭도 실행 중 생성자나 검증 함수가 되지는 않습니다.
객체 타입 정의에 타입 별칭 사용하기
타입 별칭은 특히 객체 타입을 정의할 때 매우 유용합니다.
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: "[email protected]",
registrationDate: new Date("2024-01-01"),
};
console.log(currentUser.name); // 이코딩
// newUser.registrationDate = new Date(); // Error: registrationDate는 읽기 전용입니다.직접 판단하기: 위 newUser.registrationDate를 새 Date로 교체하는 코드와, newUser.registrationDate.setFullYear(2026) 호출 중 어느 것이 타입 검사에서 허용될까요? 두 코드 모두 날짜에 관한 변경이지만 쓰기 대상이 같은지 확인하세요.
Date 속성 재할당과 내부 변경
새 Date로 registrationDate를 교체하는 쓰기는 readonly 때문에 진단됩니다. 그러나 기존 Date 객체의 setFullYear(2026) 호출은 허용됩니다. 읽기 전용인 것은 속성의 재할당 경로이고, 그 안의 객체 메서드 전체가 동결되는 것은 아닙니다. 원 예제는 현재 날짜도 사용하므로, 두 객체의 정확한 날짜 문자열이 항상 같다고 가정하지 않습니다.
이전 2장 3절에서 interface로 정의했던 Person과 거의 동일하게 User 타입을 정의했음을 알 수 있습니다.
인터페이스와 타입 별칭의 차이점
타입 별칭과 인터페이스는 객체의 타입을 정의하는 데 모두 사용될 수 있어 비슷하게 느껴질 수 있습니다.
하지만 몇 가지 중요한 차이점이 있습니다.
- 인터페이스:
extends키워드를 사용하여 다른 인터페이스를 확장할 수 있고, 클래스가implements키워드를 사용하여 인터페이스를 구현할 수 있습니다. 이는 객체 지향적인 상속과 계약 관계를 명확히 표현할 때 유리합니다. - 타입 별칭: 별칭 선언 자체는
type 이름 = 타입형태이고, 인터섹션(&)으로 객체 요구를 결합할 수 있습니다. 정적으로 알려진 멤버를 가진 객체형 별칭은 인터페이스의extends나 클래스의implements대상도 될 수 있습니다. 유니온 별칭은 이 대상이 될 수 없습니다.
// 인터페이스 확장 (extends)
interface BaseShape {
color: string;
}
interface Circle extends BaseShape {
radius: number;
}
// 타입 별칭을 이용한 '확장' (인터섹션 &)
type BaseShapeAlias = {
color: string;
};
type CircleAlias = BaseShapeAlias & {
radius: number;
};- 인터페이스: 동일한 이름의 선언을 병합(Merge)하여 멤버를 합칠 수 있습니다. 다만 같은 이름의 비함수 속성을 반복 선언하면 타입도 같아야 합니다. 아래
Car는 서로 다른brand와model을 합치는 예시이며, 함수 멤버의 오버로드 규칙과는 구분합니다. 라이브러리에서 기존 타입에 새 속성을 추가할 때 활용할 수 있습니다. - 타입 별칭: 동일한 이름으로 여러 번 선언할 수 없습니다. 즉, 재선언 시 오류가 발생합니다.
// 인터페이스 병합 예시
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 별칭을 선택할 때 확인할 기준을 프로젝트 적용 관점에서 정리한 것입니다.
TYPE / RUNTIME / CONTRACT
표현할 타입과 선언 확장 정책으로 선택한다
객체 계약은 type과 interface 둘 다 표현할 수 있습니다. 임의 타입 식이 필요한지, 같은 이름의 선언을 병합할지, 정적으로 알려진 객체 멤버를 확장·구현할지를 따로 확인합니다.
TYPE / EXPRESSION
유니온 · 튜플 · 원시 타입 별칭
StringOrNumber와 PointTuple 같은 타입 식에 이름을 붙입니다. interface로 원시 타입이나 유니온 자체를 직접 정의하지 않습니다.
INTERFACE / MERGING
같은 이름의 선언을 조건에 맞게 병합
본문 Car 두 선언은 서로 다른 brand와 model을 함께 요구합니다. 같은 이름의 비함수 속성을 반복 선언하면 타입도 같아야 하며, 단순히 한쪽 타입에 할당 가능하다는 조건으로 대신할 수 없습니다. 함수 멤버의 오버로드는 별도 규칙입니다. type Product 재선언은 진단됩니다.
BOTH / OBJECT SHAPE
객체형 alias도 확장·구현 대상
정적으로 알려진 객체 멤버를 가진 alias는 interface extends나 class implements의 대상이 될 수 있습니다. 유니온은 해당 대상이 될 수 없습니다. 실제 클래스 구현은 이 절에서 제공하지 않습니다.
EXTENDS / INTERSECTION
충돌 진단과 교차 제약을 구분
interface extends는 호환되지 않는 속성을 진단합니다. 교차 타입 &는 두 요구를 동시에 적용해 never가 될 수도 있습니다. 본문의 BaseShape/Circle과 alias 교차 예는 호환되는 color+radius입니다.
임의 타입 식과 선언 병합 요구를 구분합니다. 알려진 객체형 alias도 extends·implements의 대상이 될 수 있지만 유니온은 해당 대상이 될 수 없습니다.
타입 별칭과 인터페이스는 기능이 겹치는 부분이 많기 때문에 팀 규칙 없이 섞어 쓰면 읽는 사람이 의도를 추측해야 합니다.
언제 무엇을 사용해야 할까?
일반적인 가이드라인은 다음과 같습니다.
- 객체의 모양(Shape)을 정의하고, 향후 다른 인터페이스가 이를 확장하거나 클래스가 구현해야 할 가능성이 있다면
interface를 사용하는 것이 좋습니다. 특히 같은 이름의 선언 병합을 허용하려는 확장 정책에서는interface가 적합합니다. 객체형type도 확장·구현 대상이 될 수 있으므로, 단지 객체라는 이유만으로 어느 쪽이 항상 더 강력하다고 판단하지 않습니다. - 원시 타입, 유니온 타입, 튜플 타입 등 객체 이외의 타입을 포함하여 어떤 타입이든 간결하게 별칭을 부여하고 싶을 때는
type별칭을 사용합니다.interface로는 표현하기 어려운 복잡한 조합의 타입을 정의할 때 유용합니다.
최근 타입스크립트 버전에서는 interface와 type 별칭의 기능적 차이가 많이 줄어들었지만, 위에서 언급한 주요 차이점들은 여전히 유효합니다.
선택 연습: "loading" | "ready"에 이름을 붙이는 상태 타입과, 같은 이름의 선언을 두 번 사용해 brand와 model을 함께 요구하는 객체 계약을 각각 작성해 보세요. 후자는 객체를 자동으로 생성하는 기능인지도 설명하세요.
표현하려는 계약과 선언 정책
type ViewState = "loading" | "ready";
interface VehicleContract { brand: string; }
interface VehicleContract { model: string; }
const vehicle: VehicleContract = { brand: "예제", model: "학습용" };첫 번째는 유니온 식의 별칭이므로 type, 두 번째는 같은 이름의 선언 병합이 요구되므로 interface를 선택했습니다. 실행할 객체의 두 값을 제공하는 것은 마지막 리터럴이며 선언 자체가 값을 생성하지 않습니다.
프로젝트의 성격과 팀의 컨벤션에 따라 선택하여 사용할 수 있습니다.
이로써 타입스크립트의 기본 타입들에 대한 학습을 마쳤습니다.
숫자, 문자열, 불리언과 같은 기본 데이터부터 시작하여, 복잡한 객체와 그 형태를 정의하는 인터페이스, 그리고 유연한 타입 조합을 위한 유니온/인터섹션, 마지막으로 타입에 새 이름을 부여하는 타입 별칭까지, 타입스크립트의 견고한 타입 시스템을 위한 핵심 개념들을 살펴보았습니다.