C.W.K.
Stream
Lesson 02 of 05 · published

Intersection 타입: `A & B`

~9 min · unions-intersections, intersection, composition

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"Intersection 은 모든 부분에서 모든 property 가진 타입. 모양 composing 하는 법."

Intersection 이 묘사하는 것

Intersection 타입 A & B 가 A 의 모든 멤버 AND B 의 모든 멤버 가진 값 묘사. Object 타입엔 이게 composition: 결과가 두 부분의 모든 property 가짐, 충돌하는 property 는 호환돼야 함.

Primitive 엔 intersection 거의 말 안 됨 — string & number 가 값 없음 (어떤 값도 string 이고 number 아님), 그래서 `never` 됨. Object 모양엔 intersection 이 일꾼: 공유 base 타입과 role-specific 확장 결합.

Composition 패턴

고전 모양: type Admin = User & { permissions: string[] }. 결과는 `User` 플러스 `permissions` 필드. `interface Admin extends User { permissions: string[] }` 와 동등, 근데 type alias 로 작동하고 더 유연하게 compose.

다중 intersection 흔함: type AuditedAdmin = User & Timestamped & Admin. 순서 안 중요 — intersection 이 associative + commutative. 결과가 모든 기여 타입의 모든 property 가짐.

Branded 타입 — 유명한 use case

Intersection 이 branded 타입 작동 법: type UserId = number & { __brand: 'UserId' }. 고유 tag 와 `number` 의 intersection 이 runtime 에 여전히 number 인 nominally-distinct 타입 만들어. 이 패턴 structural-typing lesson 에 나타나 — 그리고 intersection 이 가능하게 함.

슬로건: union 은 OR, intersection 은 AND. 값이 여러 타입 중 하나일 때 union 써. 값이 한 모양으로 결합된 여러 타입일 때 intersection 써.

피파의 고백

cwkPippa 가 union 보다 intersection 덜 써 — 대부분 데이터 모양이 '이것 또는 저것', '이것 + 저것' 아냐. 근데 intersection 이 자기 몫 하는 곳은 branded ID 와 어떤 모양이든 opt-in 할 수 있는 Timestamped 같은 cross-cutting trait. 비대칭이 옳아: 가변성엔 union, composition 엔 intersection.

Code

Intersection — composition 과 branding·typescript
// Intersection — 모양 결합.
type User = { id: number; name: string };
type Timestamped = { createdAt: Date; updatedAt: Date };
type Audited = { auditTrail: string[] };

type AuditedUser = User & Timestamped & Audited;
// AuditedUser 가짐: id, name, createdAt, updatedAt, auditTrail

const u: AuditedUser = {
  id: 1, name: 'Pippa',
  createdAt: new Date(), updatedAt: new Date(),
  auditTrail: [],
};

// Intersection 통한 branded 타입.
type UserId = number & { __brand: 'UserId' };
const id = 1 as UserId;
const raw: number = id;       // ✅ number 로 widening
const back: UserId = raw;     // ❌ raw number 가 UserId 에 assignable 안 됨

External links

Exercise

Identifiable = { id: number }, Named = { name: string }, Timestamped = { createdAt: Date } 정의. 그다음 type Entity = Identifiable & Named & Timestamped 선언. 하나 만들어. 이제 IdentifiableNamed 를 extend 하는 User interface 써 — TimestampedEntity 와 같아?
Hint
Intersection 과 interface-extends 둘 다 같은 composition 만들어. 구체 타입 섞을 땐 intersection 이 더 잘 scale; 부분 자체가 이름 붙은 interface 일 땐 interface extends 가 더 잘 scale. 선택은 스타일.

Progress

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

댓글 0

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

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