TypeScript type과 interface 차이: 객체 타입을 선언할 때 무엇을 고르면 좋을까

TypeScript type과 interface 차이: 객체 타입을 선언할 때 무엇을 고르면 좋을까
TypeScript type과 interface는 객체 타입 선언에서 겹치는 부분이 많지만 확장 방식과 표현 범위가 다릅니다.

TypeScript type interface 차이는 TypeScript를 배우기 시작하면 가장 먼저 부딪히는 선택입니다.

핵심은 둘 중 하나가 항상 정답이 아니라 표현하려는 타입의 성격이 다르다는 점입니다. 이 글은 TypeScript 공식 문서를 기준으로 객체 타입 선언, declaration merging, union/intersection, 팀 컨벤션 기준을 정리합니다.

TypeScript type interface 차이 요약 카드
객체 모양을 공개 계약으로 열어둘지, 조합 타입까지 표현할지에 따라 선택이 달라집니다.

TypeScript type과 interface는 왜 비슷해 보일까

둘 다 객체의 모양을 설명할 수 있기 때문입니다. 아래 두 선언은 사용하는 쪽에서 거의 같은 느낌으로 읽힙니다.

interface UserProfile {
  id: string;
  name: string;
}

type UserProfileAlias = {
  id: string;
  name: string;
};

그래서 처음에는 `interface`와 `type`을 취향 차이로만 보기 쉽습니다. 하지만 확장 방식, 병합 가능성, 표현할 수 있는 타입 범위에서 차이가 납니다.


interface는 객체 계약을 확장하기 좋다

`interface`는 객체의 공개 모양을 선언하는 데 자연스럽습니다. 다른 interface를 상속해 확장할 수 있고, 클래스가 구현해야 하는 계약으로 쓰기도 쉽습니다.

interface Identifiable {
  id: string;
}

interface User extends Identifiable {
  name: string;
}

class AdminUser implements User {
  constructor(public id: string, public name: string) {}
}

공개 API의 object shape를 선언하거나, 라이브러리 타입을 확장할 여지를 남길 때 `interface`가 읽기 좋은 경우가 많습니다.


type alias는 더 넓은 타입 표현에 강하다

`type`은 객체 타입뿐 아니라 union, intersection, tuple, primitive 별칭까지 표현할 수 있습니다. 객체 하나의 모양보다 타입 조합 자체가 중요할 때 강합니다.

type UserId = string;
type ApiState = "idle" | "loading" | "success" | "error";
type Point = [number, number];

type UserWithRole = User & {
  role: "admin" | "member";
};

특히 상태값, 이벤트 이름, 식별자 별칭, 여러 타입의 조합처럼 객체 선언만으로 설명하기 어려운 모델에는 `type`이 잘 맞습니다.


declaration merging은 interface의 중요한 차이

TypeScript는 같은 이름의 interface 선언을 병합할 수 있습니다. 이 특징은 라이브러리의 타입 확장이나 전역 타입 보강에서 유용하지만, 팀 코드에서는 뜻하지 않은 확장이 될 수도 있습니다.

interface Window {
  appVersion: string;
}

interface Window {
  currentUserId?: string;
}

반면 같은 이름의 `type`을 다시 선언하면 오류가 납니다. 이 차이는 안정성을 높이기도 하고, 확장을 어렵게 만들기도 합니다.


둘 다 가능한 객체 타입은 어떻게 고를까

단순 객체 타입은 `interface`와 `type` 모두 가능합니다. 그래서 팀에서는 예외보다 기본 규칙이 중요합니다.

  • 공개 API나 클래스 구현 계약은 `interface`를 우선한다
  • union, tuple, primitive alias, mapped type 조합은 `type`을 우선한다
  • 라이브러리 타입 보강이 필요하면 declaration merging 가능성을 고려한다
  • 프로젝트 전체에서 일관된 규칙을 문서화한다

실무 체크리스트

  1. 객체의 공개 모양을 선언하는지 먼저 확인한다
  2. 확장과 구현 계약이 중요하면 interface를 검토한다
  3. union, intersection, tuple, primitive 별칭이면 type을 쓴다
  4. declaration merging이 장점인지 위험인지 팀 기준으로 판단한다
  5. 둘 다 가능하면 코드베이스의 기존 컨벤션을 따른다

정리

TypeScript type는 이름만 외우는 것보다 어떤 문제를 줄이기 위한 도구인지 보는 편이 좋습니다. 이 글에서는 공식 문서 기준으로 핵심 개념, 자주 하는 실수, 실무 판단 기준을 함께 정리했습니다.

함께 보면 좋은 내부 글은 자바 record는 class와 무엇이 다를까, SOLID 원칙은 왜 실무에서 자주 오해될까, 인터페이스 분리 원칙(ISP)은 왜 자주 놓칠까입니다. 외부 기준은 TypeScript Handbook – Everyday Types, TypeScript Handbook – Object Types, TypeScript Handbook – Declaration Merging를 확인했습니다.

함께보면 좋은 글