본문 바로가기

타입 별칭

복잡한 유니온·인터섹션·객체 타입에 재사용 가능한 이름을 붙이고 확장 방식에 따라 type과 interface를 선택합니다.

우리는 객체의 모양을 정의할 때 interface를 사용하는 방법을 배웠습니다.

interface는 주로 객체의 타입을 정의하고, 확장하거나 구현할 때 강력한 도구입니다.

하지만 타입스크립트에는 이 외에도 복잡한 타입을 간결하게 재사용할 수 있도록 돕는 또 다른 강력한 기능이 있는데, 바로 타입 별칭(Type Aliases)입니다.

타입 별칭은 기존에 존재하는 타입에 새로운 이름(별칭)을 부여하는 방법입니다.

이를 통해 복잡한 유니온 타입, 인터섹션 타입, 혹은 객체 리터럴 타입을 더 읽기 쉽고 관리하기 쉬운 이름으로 만들 수 있습니다.

마치 긴 주소를 짧은 별명으로 부르는 것과 같습니다.

type은 기존 타입 식에 재사용할 이름을 붙입니다. Name·Age·Id·ThreeDPoint의 계약을 확인하며 별칭이 런타임 wrapper나 validator를 생성하지 않음을 구분합니다.

TYPE / RUNTIME / CONTRACT

타입 별칭은 기존 계약에 이름을 붙인다

Name=string, Id=string|number, ThreeDPoint=Point&ZCoordinate처럼 타입 식을 재사용합니다. 별칭의 다른 이름만으로 값이 분리되거나 런타임 객체가 만들어지지는 않습니다.

타입 식의 이름과 실행 출력기존타입식→type이름→JavaScript출력3노드2간선의개념연결이다. 이름은검사에서재사용하며타입선언은출력에서제거된다. 별칭은서로다른단위를자동구별하거나런타임wrapper와validator를생성하지않는다.
기존 타입 식string · number · 객체
연결 관계기존 타입 식 · string · number · 객체 → type 이름 · 검사에서 계약 재사용
type 이름검사에서 계약 재사용
연결 관계type 이름 · 검사에서 계약 재사용 → JavaScript 출력 · 타입 선언은 제거
JavaScript 출력타입 선언은 제거
타입 식의 이름과 실행 출력 · 모바일기존타입식→type이름→JavaScript출력3노드2간선의개념연결이다. 이름은검사에서재사용하며타입선언은출력에서제거된다. 별칭은서로다른단위를자동구별하거나런타임wrapper와validator를생성하지않는다. 모바일에서도 노드와 연결 방향·독립 경로가 같다.
기존 타입 식string · number · 객체
연결 관계기존 타입 식 · string · number · 객체 → type 이름 · 검사에서 계약 재사용
type 이름검사에서 계약 재사용
연결 관계type 이름 · 검사에서 계약 재사용 → JavaScript 출력 · 타입 선언은 제거
JavaScript 출력타입 선언은 제거

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;
};
재선언 (Declaration Merging)
  • 인터페이스: 동일한 이름의 선언을 병합(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 별칭을 선택할 때 확인할 기준을 프로젝트 적용 관점에서 정리한 것입니다.

임의 타입 식과 선언 병합 요구를 구분합니다. 알려진 객체형 alias도 extends·implements의 대상이 될 수 있지만 유니온은 해당 대상이 될 수 없습니다.

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를 선택했습니다. 실행할 객체의 두 값을 제공하는 것은 마지막 리터럴이며 선언 자체가 값을 생성하지 않습니다.

프로젝트의 성격과 팀의 컨벤션에 따라 선택하여 사용할 수 있습니다.


이로써 타입스크립트의 기본 타입들에 대한 학습을 마쳤습니다.

숫자, 문자열, 불리언과 같은 기본 데이터부터 시작하여, 복잡한 객체와 그 형태를 정의하는 인터페이스, 그리고 유연한 타입 조합을 위한 유니온/인터섹션, 마지막으로 타입에 새 이름을 부여하는 타입 별칭까지, 타입스크립트의 견고한 타입 시스템을 위한 핵심 개념들을 살펴보았습니다.