interface는 객체의 구조를 선언 하는 것이고, type어떤 타입이든 별칭 을 붙이는 것입니다.

면접에서 "interface와 type의 차이가 뭔가요?"라는 질문이 정말 자주 나옵니다. 대부분의 경우 둘 다 사용할 수 있지만, 미묘한 차이가 있습니다.

공통점 — 둘 다 가능한 것

객체 타입 정의

TYPESCRIPT
// 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 };

함수 타입 정의

TYPESCRIPT
// interface
interface Greeting {
  (name: string): string;
}

// type (더 직관적)
type GreetingType = (name: string) => string;

const greet: Greeting = (name) => `안녕, ${name}!`;
const greet2: GreetingType = (name) => `안녕, ${name}!`;

제네릭

TYPESCRIPT
interface Box<T> {
  value: T;
}

type BoxType<T> = {
  value: T;
};

implements

TYPESCRIPT
interface Printable {
  print(): void;
}

type Loggable = {
  log(): void;
};

// 둘 다 implements 가능
class Document implements Printable, Loggable {
  print() { console.log('프린트'); }
  log() { console.log('로그'); }
}

차이점 — interface만 되는 것

선언 병합(Declaration Merging)

TYPESCRIPT
// 같은 이름의 interface를 여러 번 선언하면 자동으로 합쳐짐
interface Window {
  myCustomProp: string;
}

// 기존 Window 인터페이스에 myCustomProp이 추가됨
// 라이브러리 타입을 확장할 때 유용

// ❌ type은 같은 이름으로 재선언 불가
// type Duplicate = { a: string };
// type Duplicate = { b: number }; // Error: Duplicate identifier

이것이 가장 큰 차이입니다. 라이브러리의 전역 타입을 확장할 때는 interface의 선언 병합이 필수입니다.

extends로 확장

TYPESCRIPT
interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

// 여러 인터페이스를 동시에 확장 가능
interface Guide extends Animal, Dog {
  level: number;
}

type도 인터섹션(&)으로 확장할 수 있지만, extends가 더 명확합니다.

차이점 — type만 되는 것

유니온 타입

TYPESCRIPT
// type만 가능
type Status = 'loading' | 'success' | 'error';
type StringOrNumber = string | number;

// interface로는 유니온을 만들 수 없음

원시 타입 별칭

TYPESCRIPT
type Name = string;
type Age = number;
type ID = string | number;

튜플 타입

TYPESCRIPT
type Coordinate = [number, number];
type RGB = [number, number, number];

Mapped Types

TYPESCRIPT
type ReadonlyUser = {
  readonly [K in keyof User]: User[K];
};

Conditional Types

TYPESCRIPT
type IsString<T> = T extends string ? 'yes' : 'no';

확장 방식 비교

TYPESCRIPT
// interface: extends 키워드
interface Base {
  id: number;
}

interface Extended extends Base {
  name: string;
}

// type: & (인터섹션)
type BaseType = {
  id: number;
};

type ExtendedType = BaseType & {
  name: string;
};

에러 메시지 차이

인터섹션으로 충돌이 발생하면 never가 되지만, extends는 명확한 에러를 줍니다.

TYPESCRIPT
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 Typestype
React Propsinterface 또는 type (팀 컨벤션)
TYPESCRIPT
// 실무에서 많이 보는 조합
interface UserProps {           // 객체 구조는 interface
  name: string;
  role: UserRole;               // 유니온은 type
}

type UserRole = 'admin' | 'user' | 'guest';
type ApiResponse<T> = {         // 제네릭 유틸리티는 type
  data: T;
  error: string | null;
};

정리

  • interfacetype 대부분의 경우 호환되지만 미묘한 차이가 있다
  • interface만의 강점: 선언 병합, extends의 명확한 에러
  • type만의 강점: 유니온, 튜플, Mapped/Conditional Types
  • 팀 컨벤션이 없다면, 객체 구조는 interface, 나머지는 type이 일반적이다
  • 면접에서는 "선언 병합"과 "유니온 타입" 두 가지 차이만 알면 충분하다
댓글 로딩 중...