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

`type` Alias: 모양에 이름 붙이기

~10 min · types-interfaces, type-alias, naming

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"Type alias 는 모양의 이름일 뿐. 모양이 실제 것."

`type` 이 진짜 뭐 함

`type` 선언은 기존 타입에 새 이름 도입. type UserId = numberUserId 이름 만들고 쓰이는 곳마다 number 로 resolve. 새 타입 아냐 — `UserId` 와 `number` 가 어디서나 호환. Alias 는 reader 용, compiler 용 아냐.

근데 alias 가 약하진 않아. 오른쪽이 primitive 이상이 되면 강해져. type Status = 'idle' | 'loading' | 'done' 은 literal union 에 이름. type Callback = (msg: string) => void 은 함수 signature 에 이름. type Tree<T> = { value: T; children: Tree<T>[] } 는 재귀 모양에 이름. 어느 것도 타협 없이 interface 와 동등한 거 없어.

`type` 이 옳은 tool 인 3자리

1. Union 과 intersection. type StringOrNumber = string | number, type Combined = A & B. Interface 는 union 표현 전혀 못 하고, intersection 도 겨우 (`extends` 통해서) 표현.

2. 기존 타입에서 derive 한 타입. type UserKeys = keyof User, type UserEmail = User['email'], type Awaited2 = Awaited<Promise<string>>. 이 계산들 `type` 필요 — `interface` 가 host 못 함.

3. 단독 함수 타입. type Handler = (event: Event) => void 가 동등한 interface (interface Handler { (event: Event): void }, 모호한 call-signature 문법 씀) 보다 깨끗하게 읽혀.

`type` 과 `interface` 가 겹치는 곳

일반 object 모양엔 — 대부분 developer 가 가장 자주 손 뻗는 거 — typeinterface 가 거의 동등:

type UserA = { id: number; name: string };
interface UserB { id: number; name: string }

둘 다 같은 체크로 compile. 둘 다 `extends` 가능 (interface 는 `extends User`, type 은 intersection `& User`). 둘 다 export 가능. 차이는 스타일, 능력 아냐 — 이 overlap 안에선.

경험 법칙: 일반 object 모양 아닐 때마다 `type` 써. Union, intersection, 함수 타입, derived 타입, conditional 타입, mapped 타입 — 다 type 원해. 일반 object 모양이 유일한 overlap 지역, 거기선 스타일 결정.

Alias 의 재귀 타입

`type` 의 가장 유용한 거 중 하나는 자기 참조 가능. type Tree<T> = { value: T; children: Tree<T>[] } 는 재귀 tree 모양 정의. 재귀 참조 괜찮아, TypeScript 가 lazy 하게 resolve 하니까. Interface 도 이거 가능하지만, 재귀 타입의 모양 선언이 자주 `type` 으로 더 깨끗하게 읽혀.

피파의 고백

cwkPippa frontend 에 대부분 export 가 `interface` 가 아니라 `type` 인 `types.ts` 파일 있어. 이유 기계적: 많은 타입이 union (`type BrainName = 'claude' | 'codex' | 'gemini' | 'ollama'`) 이거나 API 응답에서 derived (`type ChatMessage = Awaited<ReturnType<typeof fetchMessage>>`). 순수 object 모양엔 codebase 가 가끔 여전히 `interface` 쓰지만, 표현되는 대부분이 순수 object 모양 아니라서 `type` 이 default.

Code

`type` 이 유일한 선택인 곳·typescript
// `type` 이 유일한 선택인 자리들.

// Union
type Color = 'red' | 'green' | 'blue';

// Intersection
type WithTimestamp<T> = T & { createdAt: Date };

// 함수 타입
type Comparator<T> = (a: T, b: T) => number;

// 다른 타입에서 derived
type UserPartial = Partial<User>;
type UserKeys = keyof User;
type UserEmail = User['email'];

// 재귀
type JSONValue =
  | string
  | number
  | boolean
  | null
  | JSONValue[]
  | { [key: string]: JSONValue };

// Conditional
type IsString<T> = T extends string ? true : false;
type A = IsString<'hi'>;  // true
type B = IsString<42>;    // false
Overlap, 그다음 차이·typescript
// Interface 와의 overlap, 그다음 차이.

// 일반 object 모양 — 둘 다 작동, 스타일로 선택.
type UserA = {
  id: number;
  name: string;
};

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

// 둘 다 extend 가능.
type UserAWithEmail = UserA & { email: string };
interface UserBWithEmail extends UserB { email: string }

// 이제 차이: `type` 만 union 가능.
type Status = 'idle' | 'loading' | 'done';   // ✅
// interface Status = 'idle' | 'loading' | 'done';  // ❌ 문법 에러

// 그리고 `interface` 만 두 번 선언되고 merge 가능.
interface Box { width: number }
interface Box { height: number }   // height 추가 — 같은 Box 에 merge
// type Box = { width: number };
// type Box = { height: number };   // ❌ Duplicate identifier

External links

Exercise

id: number, body: string, replies: Comment[] 가진 재귀 Comment 타입 만들어. 그다음 tree 걸어가서 모든 comment (root + 모든 descendant) 세는 countAll(c: Comment): number 함수 써. interface 가 이거 표현 가능? 같은 모양을 interface 로 쓰고 뭐 바뀌는지 봐.
Hint
재귀 참조 typeinterface 도 작동. Comment 모양을 다른 종류와 union 도 원했으면 차이가 나타나 — 예: type Node = Comment | Reaction. 그 union 은 type 에 속해.

Progress

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

댓글 0

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

아직 댓글이 없어요. 첫 댓글을 남겨보세요.