"둘은 경쟁 언어가 아니야. 겹치는 영역이 넓고, 몇 가지 가장자리에서만 선택이 갈려."
평범한 객체에서는 거의 같다
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 확장 관계를 컴파일러가 캐시해 유리할 수 있지만 일반 제품 코드에서 체감 성능을 단정할 근거는 아니야. 실제 측정이 생기기 전에는 일관성과 읽기 쉬운 계약을 우선해.
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.