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를 써야 하나?’라는 고민이 있는데, 실제로는 겹치는 부분이 많으며, 상황과 팀 코드 스타일에 따라 다를 수 있습니다.
다만 언어가 제공하는 기능적 차이와 자주 쓰이는 패턴을 자세히 알아두면, 더 합리적인 선택을 할 수 있습니다.