interface vs type — 언제 뭘 쓰고, 진짜 차이는 뭔가
interface는 객체의 구조를 선언 하는 것이고,type은 어떤 타입이든 별칭 을 붙이는 것입니다.
면접에서 "interface와 type의 차이가 뭔가요?"라는 질문이 정말 자주 나옵니다. 대부분의 경우 둘 다 사용할 수 있지만, 미묘한 차이가 있습니다.
공통점 — 둘 다 가능한 것
객체 타입 정의
// interface
interface User {
name: string;
age: number;
}
// type
type UserType = {
name: string;
age: number;
};
// 사용법은 동일
const user1: User = { name: '홍길동', age: 25 };
const user2: UserType = { name: '김철수', age: 30 };
함수 타입 정의
// interface
interface Greeting {
(name: string): string;
}
// type (더 직관적)
type GreetingType = (name: string) => string;
const greet: Greeting = (name) => `안녕, ${name}!`;
const greet2: GreetingType = (name) => `안녕, ${name}!`;
제네릭
interface Box<T> {
value: T;
}
type BoxType<T> = {
value: T;
};
implements
interface Printable {
print(): void;
}
type Loggable = {
log(): void;
};
// 둘 다 implements 가능
class Document implements Printable, Loggable {
print() { console.log('프린트'); }
log() { console.log('로그'); }
}
차이점 — interface만 되는 것
선언 병합(Declaration Merging)
// 같은 이름의 interface를 여러 번 선언하면 자동으로 합쳐짐
interface Window {
myCustomProp: string;
}
// 기존 Window 인터페이스에 myCustomProp이 추가됨
// 라이브러리 타입을 확장할 때 유용
// ❌ type은 같은 이름으로 재선언 불가
// type Duplicate = { a: string };
// type Duplicate = { b: number }; // Error: Duplicate identifier
이것이 가장 큰 차이입니다. 라이브러리의 전역 타입을 확장할 때는 interface의 선언 병합이 필수입니다.
extends로 확장
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// 여러 인터페이스를 동시에 확장 가능
interface Guide extends Animal, Dog {
level: number;
}
type도 인터섹션(&)으로 확장할 수 있지만, extends가 더 명확합니다.
차이점 — type만 되는 것
유니온 타입
// type만 가능
type Status = 'loading' | 'success' | 'error';
type StringOrNumber = string | number;
// interface로는 유니온을 만들 수 없음
원시 타입 별칭
type Name = string;
type Age = number;
type ID = string | number;
튜플 타입
type Coordinate = [number, number];
type RGB = [number, number, number];
Mapped Types
type ReadonlyUser = {
readonly [K in keyof User]: User[K];
};
Conditional Types
type IsString<T> = T extends string ? 'yes' : 'no';
확장 방식 비교
// interface: extends 키워드
interface Base {
id: number;
}
interface Extended extends Base {
name: string;
}
// type: & (인터섹션)
type BaseType = {
id: number;
};
type ExtendedType = BaseType & {
name: string;
};
에러 메시지 차이
인터섹션으로 충돌이 발생하면 never가 되지만, extends는 명확한 에러를 줍니다.
type A = { x: number };
type B = { x: string };
type C = A & B; // x: never (number & string)
// 에러가 아니라 사용할 때 문제가 됨
interface IA { x: number; }
// interface IB extends IA { x: string; } // ❌ 바로 에러 발생
공부하다 보니 이 차이가 실무에서 중요하더라고요. extends는 충돌을 바로 알려주지만, 인터섹션은 never로 만들어서 나중에 원인 파악이 어렵습니다.
성능 차이
TypeScript 컴파일러 팀에 따르면, **interface가 type보다 타입 체크 성능이 약간 더 좋습니다 **. interface는 캐싱이 잘 되지만, 인터섹션 타입은 매번 평탄화(flattening)를 해야 하기 때문입니다.
다만 이 차이는 대규모 프로젝트가 아니면 체감하기 어렵습니다.
실무에서의 선택 기준
| 상황 | 추천 |
|---|---|
| 객체 구조 정의 | interface |
| 유니온, 튜플, 원시 타입 별칭 | type |
| 라이브러리 타입 확장 | interface (선언 병합) |
| Mapped Types, Conditional Types | type |
| React Props | interface 또는 type (팀 컨벤션) |
// 실무에서 많이 보는 조합
interface UserProps { // 객체 구조는 interface
name: string;
role: UserRole; // 유니온은 type
}
type UserRole = 'admin' | 'user' | 'guest';
type ApiResponse<T> = { // 제네릭 유틸리티는 type
data: T;
error: string | null;
};
정리
interface와type대부분의 경우 호환되지만 미묘한 차이가 있다interface만의 강점: 선언 병합,extends의 명확한 에러type만의 강점: 유니온, 튜플, Mapped/Conditional Types- 팀 컨벤션이 없다면, 객체 구조는
interface, 나머지는type이 일반적이다 - 면접에서는 "선언 병합"과 "유니온 타입" 두 가지 차이만 알면 충분하다
댓글 로딩 중...