TypeScript에서
type
과 interface
는 모두 타입을 정의할 때 사용합니다. 둘 다 객체의 구조를 기술하거나, 특정 형태를 정의할 수 있다는 점에서 비슷하지만, 미묘한 차이와 상황별 유용성이 다릅니다. 아래에서 주요 차이점 및 쓰임새를 자세히 살펴보겠습니다.1.
type
과 interface
의 정의1.1
type
(타입 별칭, Type Alias)type
키워드는 새로운 타입을 정의하는 것이 아니라 기존의 타입에 별칭(Alias) 을 붙이는 역할을 합니다.즉, 기본 타입, 객체 타입, 유니온, 인터섹션(교차 타입) 등 다양한 형태를 표현할 때 사용됩니다.
특징:
✅ 유니온(
|
), 인터섹션(&
), 조건부 타입, 매핑된 타입 등을 지원✅
type
자체를 변경할 수 없음 (선언 병합 미지원)// 기본 객체 타입 정의 type Person = { name: string; age: number; }; // 유니온 타입 예시 type InputValue = string | number; // 튜플 타입 정의 type RGB = [number, number, number]; // 인터섹션(교차) 타입 type Admin = Person & { role: string; }; // 조건부 타입 type IsString<T> = T extends string ? true : false;
1.2
interface
(인터페이스)interface
는 객체의 구조(프로퍼티, 메서드)를 정의하는데 특화된 타입입니다.주로 객체, 클래스의 구조를 정의할 때 사용되며,
implements
키워드와 함께 클래스에 적용할 수 있습니다.특징:
✅
extends
를 사용하여 다른 인터페이스 확장 가능✅ 선언 병합(Declaration Merging) 지원 → 같은 이름으로 여러 번 선언하여 확장 가능
✅ 클래스에서
implements
로 사용 가능// 객체 타입 정의 interface Person { name: string; age: number; } // 인터페이스 확장 interface Admin extends Person { role: string; } // 클래스에서 인터페이스 구현 class User implements Person { constructor(public name: string, public age: number) {} }
2.
type
vs interface
비교비교 항목 | type (타입 별칭) | interface (인터페이스) |
객체 정의 | 가능 | 가능 |
**유니온(` | `) 사용** | 가능 |
인터섹션( & ) 사용 | 가능 | 가능 ( extends 로 확장) |
선언 병합(Declaration Merging) | 불가능 | 가능 (동일한 이름으로 확장 가능) |
클래스에서 implements | 불가능 | 가능 |
매핑된 타입 (Mapped Types) | 가능 | 불가능 |
조건부 타입 (Conditional Types) | 가능 | 불가능 |
3.
type
과 interface
의 확장 방법3.1
type
확장 (&
연산자 사용)타입을 확장하려면 인터섹션(
&
)을 사용해야 합니다.type Person = { name: string; age: number; }; type Admin = Person & { role: string; }; const admin: Admin = { name: "Alice", age: 30, role: "SuperAdmin", };
3.2
interface
확장 (extends
사용)인터페이스는
extends
키워드로 확장할 수 있습니다.interface Person { name: string; age: number; } interface Admin extends Person { role: string; } const admin: Admin = { name: "Alice", age: 30, role: "SuperAdmin", };
✅
interface
확장 방식이 더 직관적이므로 객체 구조를 확장할 때 주로 사용됩니다.4.
type
과 interface
의 차이점4.1 유니온(
|
) 및 튜플 지원 여부✅
type
은 유니온(|
)과 튜플을 정의할 수 있음✅
interface
는 유니온(|
)을 지원하지 않음// 유니온 타입 (type만 가능) type ResponseStatus = "success" | "error"; const status: ResponseStatus = "success"; // ✅ 가능 // 튜플 타입 (type만 가능) type Coordinate = [number, number]; const point: Coordinate = [10, 20]; // ✅ 가능
인터페이스는 유니온 타입을 직접 지원하지 않음.
// ❌ 인터페이스에서는 유니온 타입을 직접 정의할 수 없음 interface ResponseStatus { status: "success" | "error"; // ✅ 하지만 객체 내 프로퍼티로 유니온 타입은 가능 }
4.2 선언 병합 (Declaration Merging)
✅
interface
는 같은 이름으로 여러 번 선언하면 자동 병합됨✅
type
은 같은 이름으로 중복 선언할 수 없음 (컴파일 에러 발생)// 인터페이스 선언 병합 (자동으로 속성이 합쳐짐) interface User { name: string; } interface User { age: number; } const user: User = { name: "Alice", age: 25 }; // ✅ 가능
// 타입 별칭은 병합되지 않음 (에러 발생) type User = { name: string; }; type User = { age: number; // ❌ 오류: 중복된 식별자 };
5. 언제
type
과 interface
를 사용해야 할까?상황 | type 추천 | interface 추천 |
**유니온(` | `)이나 튜플을 사용할 때** | ✅ 가능 |
객체의 구조를 정의할 때 | 가능 | ✅ 추천 |
클래스( implements )와 함께 사용할 때 | ❌ 불가능 | ✅ 추천 |
여러 번 확장할 가능성이 있는 경우 | ❌ 불가능 | ✅ 추천 (선언 병합 가능) |
조건부 타입(Conditional Types) 필요할 때 | ✅ 추천 | ❌ 불가능 |
API 응답 타입을 정의할 때 | ✅ 추천 | 가능하지만 추천되지 않음 |
5.1
type
을 사용해야 하는 경우- 유니온(
|
)이나 인터섹션(&
)이 필요한 경우
- 복잡한 조건부 타입을 사용할 때
- 매핑된 타입이 필요한 경우
type ApiResponse<T> = T extends "success" ? { status: "success"; data: string } : { status: "error"; message: string };
5.2
interface
를 사용해야 하는 경우- 객체 구조를 정의할 때
- 확장 가능성이 있는 경우 (선언 병합 활용)
- 클래스(
implements
)와 함께 사용할 때
interface ApiResponse { status: "success" | "error"; message?: string; data?: string; }
6. 결론
대부분 ‘어떤 경우에 type를 써야 하고, 어떤 경우에 interface를 써야 하나?’라는 고민이 있는데, 실제로는 겹치는 부분이 많으며, 상황과 팀 코드 스타일에 따라 다를 수 있습니다.
다만 언어가 제공하는 기능적 차이와 자주 쓰이는 패턴을 자세히 알아두면, 더 합리적인 선택을 할 수 있습니다.