C.W.K.
Stream
Lesson 03 of 06 · published

`type` vs `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
"인터넷이 이걸 성전 (聖戰) 처럼 다뤄. 사실은 좁은 비대칭 2개 가진 스타일 선택."

이미 본 거

둘 다 만났어. Object 모양엔 많이 overlap 하는 거 봤어. 두 비대칭 봤어:

  • type: union, 임의 타입의 intersection, mapped 타입, conditional 타입, template literal 타입, `keyof`/`typeof`/indexed access 통한 derived 타입.
  • interface: declaration merging (global augment 와 library 타입 augment 포함).

순수 object 모양엔 기능적으로 동등. 선택은 스타일.

95% case 해결하는 cheat sheet

원하는 거…쓸 거…
Union 타입type
단독 함수 signaturetype
Derived 타입 (Partial, ReturnType, keyof, …)type
Conditional 또는 mapped 타입type
Public API object 모양interface (스타일)
3rd-party 타입 확장interface (declaration merging)
일반 내부 object 모양아무거나 — 하나 골라, 일관성 유지

에러 메시지가 어느 거 쓸지 말해

이게 가장 구체적인 규칙. Compile 할 때 에러 메시지 봐. Interface 는 선언된 이름으로 나타나 (`Type 'A' is missing the property 'foo' from type 'User'`). Type alias 는 확장된 채로 나타나 (`Type '{ id: number }' is missing the property 'foo' from type '{ id: number; foo: string }'`). Public API 모양엔 이름 붙은 버전이 에러 읽는 developer 한테 훨씬 나은 경험.

솔직한 입장: 둘 다 작동. 팀 convention 골라, 적어, 토론 그만. 인터넷 곳곳에서 이 질문에 쓴 시간이 실제 logic 버그에 썼으면 더 나았을 거.

성능 — 지루한 실제 차이

매우 큰 타입엔 `interface` 가 동등한 intersected `type` alias 보다 타입 체크 살짝 더 빠를 수. 이유: interface extension 이 fast path 가진 인식된 패턴; intersection 은 범용 tool. 실제로 이게 중요한 건 수백 개 타입 가진 monorepo, 개별 파일 아냐. `tsc --noEmit` 이 갑자기 느리면 체크할 거 중 하나.

피파의 고백

cwkPippa convention: API 에서 오거나 codebase 전반에 이름 붙은 contract 로 소비되는 모양엔 interface. Union, derived 타입, 함수 signature, 일회성 local 모양엔 type. 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 에 추가
}
API 모양엔 interface 이기는 이유 — 에러 가독성·typescript
// 에러 메시지 가독성 — 실제 tiebreaker.

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

const missing1: User = { id: 1 };   // 에러가 "User" 이름으로 언급
//      ^ 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 '{ id: number; email: string; }'.

// Interface 버전이 public API 엔 더 잘 읽혀.
// Type alias 버전도 내부 모양엔 여전히 잘 작동.

External links

Exercise

작은 프로젝트의 어떤 TypeScript 파일 들고 와. 모든 type/interface 선언 list. 각각 결정을 'type 필수' (예: union), 'interface 필수' (예: global 확장), '스타일 선택' 으로 분류. 스타일 선택 몇 개고, 파일이 그것들에 일관적이야?
Hint
대부분 파일이 80%+ 스타일 선택. 질문은 '뭐가 맞아' 가 아니라 '파일이 내부 일관성 있어'. 절반 object 모양이 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 문장은 업데이트가 필요하네요 — 잡아줘서 고마워요.