type vs interface: 확장성과 성능, 우리 팀의 선택 기준은?

타입스크립트 프로젝트를 시작할 때, 팀원들 사이에서 가장 먼저 엇갈리는 의견이 있다. 바로 객체의 타입을 정의할 때 무엇을 사용할 것인가이다.
// 무엇이 다를까?
type User = {
name: string;
}
interface User {
name: string;
}기능적으로 보면 90% 이상의 상황에서 둘은 똑같이 동작한다. 그렇다면 아무거나 써도 되는 걸까? 아니면 크리스가 모르는 성능상의 비밀이 숨겨져 있을까?
오늘은 type과 interface의 결정적인 차이점과, 상황에 따른 올바른 선택 기준을 정리한다.
1. 선언 병합 (Declaration Merging)
가장 큰 차이점은 "확장성"에 있다.
크리스가 오픈소스 라이브러리를 만들고 있다고 가정해보자. 사용자가 라이브러리의 설정을 덮어쓰거나 추가해야 하는 상황이라면 interface가 필수적이다.
Interface: 열려 있는 설계도
interface는 같은 이름으로 여러 번 선언하면, 타입스크립트가 알아서 이들을 하나로 합쳐준다. 이를 선언 병합이라고 한다.
// global-window.d.ts
// 1. 기존의 Window 인터페이스
interface Window {
title: string;
}
// 2. 내가 추가한 속성 (에러 없음, 자동 병합됨)
interface Window {
googleAnalyticsId: string;
}
// ✅ 결과: Window는 title과 googleAnalyticsId를 모두 가짐
const w: Window = window;
w.googleAnalyticsId = 'UA-XXXX';Type: 닫혀 있는 별칭
반면 type은 재선언이 불가능하다. 엄격하게 "이 이름은 이미 선점되었다"고 경고한다.
// config.ts
type UserConfig = {
theme: 'dark' | 'light';
}
// ❌ Error: Duplicate identifier 'UserConfig'.
type UserConfig = {
apiKey: string;
}이러한 특성 때문에, 라이브러리의 타입 정의(ex. @types/react)나 전역 객체 확장에는 반드시 interface를 사용해야 한다.
2. 표현력의 차이 (Union & Tuple)
type은 interface가 할 수 없는 강력한 기능을 가지고 있다. 바로 유니온 타입(Union)과 원시 값(Primitive) 정의다.
// api-types.ts
// 1. 유니온 타입: interface로는 표현 불가
type Status = 'pending' | 'success' | 'error';
// 2. 튜플 타입
type Coordinates = [number, number];
// 3. 원시 타입 별칭
type UUID = string;interface는 오직 객체(Object)의 구조를 정의하는 데 특화되어 있다. 반면 type은 데이터를 담는 모든 형태에 이름을 붙일 수 있는 만능 라벨기와 같다.
3. 성능 이슈: 정말 차이가 날까?
흔히 "인터페이스가 타입보다 성능이 좋다"는 이야기를 듣곤 한다. 이것은 사실일까?
과거에는 interface가 컴파일 속도 면에서 확실히 빨랐다. 하지만 최신 타입스크립트 버전에서는 그 차이가 미미해졌다. 다만, 구조적인 차이로 인해 interface가 여전히 유리한 점은 있다.
따라서 매우 복잡한 객체 타입을 다루는 대규모 프로젝트라면 interface를 사용하는 것이 컴파일 성능과 에러 디버깅에 미세하게 유리하다.
4. 우리 팀의 선택 기준 (Best Practice)
그렇다면 실무에서는 어떻게 정해야 할까? 공식 문서와 커뮤니티의 관례를 종합하여 다음과 같은 기준을 제안한다.
전략: Interface First, Type for Specifics
// ✅ 좋은 예시: user.ts
// 객체 구조는 interface
interface User {
id: number;
name: string;
}
// 상태값 등은 type
type UserRole = 'admin' | 'member' | 'guest';
// 함수 타입은 취향이지만, type이 조금 더 간결함
type UpdateUser = (user: User) => void;핵심 정리
결국 "객체의 뼈대는 interface로, 복잡한 조합은 type으로" 접근하는 것이 가장 합리적인 전략이다.
🔗 참고 링크
다음 글 예고:
자바스크립트의 동작 원리를 알았으니, 이제 타입을 더해 견고한 코드를 만들 차례다.
"type vs interface: 확장성과 성능, 우리 팀의 선택 기준은?" 편에서 계속된다.