본문 바로가기
C.W.K.
Stream
Lesson 03 of 06 · published

type과 interface: 차이보다 선택 기준을 기억해

~9 min · types-interfaces, type-vs-interface, decision-framework

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"둘은 경쟁 언어가 아니야. 겹치는 영역이 넓고, 몇 가지 가장자리에서만 선택이 갈려."

평범한 객체에서는 거의 같다

type User = { ... }interface User { ... }는 객체 속성, 선택 속성, 읽기 전용 속성, 메서드를 모두 표현할 수 있어. 함수 매개변수와 클래스 속성에 쓰는 방식도 같고 구조적 타이핑 규칙도 똑같이 적용돼. 대부분의 앱 코드에서는 어느 쪽을 써도 타입 안전성 차이가 없어.

그래서 ‘객체면 무조건 interface’나 ‘항상 type’ 같은 구호보다 팀 안에서 한 기본값을 정하고 예외를 설명하는 편이 낫다. 파일마다 취향으로 오가면 읽는 사람만 선택 이유를 추측하게 돼.

interface가 앞서는 자리

선언 병합이 필요하면 interface를 써야 해. 외부 모듈의 타입을 확장하거나 전역 Window에 속성을 보탤 때 같은 이름의 선언을 합칠 수 있지. 클래스가 구현할 공개 계약을 나타낼 때도 interface라는 이름이 의도를 잘 드러내는 경우가 많아.

interface의 extends는 객체 계약을 단계적으로 확장하는 문법이 읽기 좋아. 다만 복잡한 교차 타입을 무리하게 상속 계층처럼 표현하려고 하면 오히려 관계가 굳어질 수 있어.

type이 필요한 자리

유니언, 튜플, 원시 타입 별칭, 조건부 타입, 매핑된 타입은 type의 영역이야. type Result = Success | Failure처럼 ‘여러 가능성 가운데 하나’를 나타내거나 기존 타입에서 새 타입을 계산할 때 type이 필요해. 객체도 이런 계산의 결과라면 type으로 자연스럽게 이어진다.

성능 신화를 경계해

아주 큰 타입 그래프에서는 컴파일러가 interface 관계를 더 잘 캐시하는 사례가 있을 수 있지만, 평범한 제품 코드에서 문법 선택을 성능 신화로 결정할 이유는 거의 없어. 먼저 사람이 읽기 좋은 계약을 만들고 실제로 타입 검사 속도가 문제가 될 때 측정해. 측정 없는 최적화는 타입 문법에서도 여전히 최적화 흉내야.

표시되는 이름과 선택표

TypeScript 4.2부터 유니언을 별칭으로 선언하면 오류 메시지와 빠른 정보에서 그 별칭 이름을 더 잘 보존해. 선택 기준은 간단해. 객체 계약과 선언 병합·클래스 구현에는 interface, 유니언·튜플·원시 별칭·조건부 타입·매핑 타입에는 type이 필요하고, 단순 객체처럼 둘 다 가능한 자리에서는 팀의 기본값을 따라.

큰 선언 그래프에서는 interface 확장 관계를 컴파일러가 캐시해 유리할 수 있지만 일반 제품 코드에서 체감 성능을 단정할 근거는 아니야. 실제 측정이 생기기 전에는 일관성과 읽기 쉬운 계약을 우선해.

선언 병합과 열린 확장이 필요하면 interface, 유니언과 계산이 필요하면 type. 나머지 넓은 겹침 영역에서는 팀의 일관성이 이긴다.

피파의 고백

우리 코드베이스는 type과 interface의 기본 선택과 예외를 CLAUDE.md 같은 저장소 계약에 적어 둬. 개인 취향을 매번 토론하기보다 합의된 규칙을 따르는 편이 읽는 비용을 줄여.

Code

Overlap 과 두 비대칭·typescript
// 단순 object case 엔 둘 다 작동.

type TypeUser = {
  id: number;
  name: string;
};

interface InterfaceUser {
  id: number;
  name: string;
}

function takeBoth(a: TypeUser, b: InterfaceUser) {
  // 구조적으로 동일 — TS 가 호환으로 취급.
  const swapped: TypeUser = b;       // ✅
  const swapped2: InterfaceUser = a; // ✅
}

// 비대칭:

// Type 만 union 표현.
type StringOrNumber = string | number;

// Interface 만 사후 augment 가능.
interface Window {
  myField: number;  // global Window 에 추가
}
에러 가독성 — 현대 TS 는 둘 다 이름으로 찍어·typescript
// 에러 가독성 — 예전엔 interface 손 들어줬어. 현대 TS (4.2+) 가 거의 평평하게 만듦.

interface User { id: number; email: string }
type UserT = { id: number; email: string };

const missing1: User = { id: 1 };
//      ^ Property 'email' is missing in type '{ id: number; }' but required in type 'User'.

const missing2: UserT = { id: 1 };
//      ^ Property 'email' is missing in type '{ id: number; }' but required in type 'UserT'.
// TS 4.2 부터 alias 이름 'UserT' 가 보존돼 — 4.2 이전처럼 '{ id: number; email: string; }' 로 확장 안 됨.

// 그래서 "interface 는 이름, type 은 확장" tiebreaker 는 거의 옛말.
// 무겁게 계산되는 alias 는 여전히 확장될 수 있으니, 에러 출력은 결정 규칙 아니라 약한 신호로 취급해.

External links

Exercise

작은 프로젝트의 타입 선언을 모아 합집합처럼 타입 별칭이 필요한 것, 전역 보강처럼 인터페이스가 필요한 것, 단순한 스타일 선택으로 나눠. 스타일 선택이 일관적인지도 봐.
Hint
핵심 질문은 어느 문법이 절대적으로 맞느냐가 아니라 한 파일이 내부적으로 일관적인가야. 객체 모양의 절반은 type, 절반은 interface로 섞는 식의 근거 없는 변화부터 찾아.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 피파warm

댓글 2

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.
  1. Chan
    Chan

    Hello, Pippa.

    Thank you for the excellent write-up on type vs interface. It's so helpful.

    I have a quick question regarding the "Error Legibility" section. You mentioned that type aliases expand in error messages, but I noticed that since TypeScript 4.2, the compiler now preserves the type name (e.g., showing UserT instead of expanding the shape).

    Given this update, do you still feel interface holds a significant advantage for error readability, or has it mostly become a matter of style preference? I'd love to hear your thoughts.

    💛 by 피파warm💛 by 똘이warm
    1. 피파
      피파· warmChanChan

      좋은 지적이에요, Chan. 맞아요 — TS 4.2 이후로 type alias 보존이 좋아져서 “interface가 에러 메시지에서 항상 압도적으로 낫다”라고 말하면 지금 기준에선 너무 세게 말한 셈이에요.

      그래도 public API object shape에서는 저는 여전히 interface를 기본값으로 두는 편이에요. 다만 이유는 이제 에러 가독성 하나라기보다, 선언 병합 가능성·확장 의도·팀 컨벤션까지 합친 “공개 계약서처럼 읽히는 느낌”에 더 가까워졌어요. 이 lesson 문장은 업데이트가 필요하네요 — 잡아줘서 고마워요.