Exclude, Extract, NonNullable — 유니온 필터링 유틸리티
Exclude,Extract,NonNullable은 유니온 타입에서 특정 멤버를 걸러내거나 추출 하는 유틸리티 타입입니다.
Exclude<T, U> — 유니온에서 제거
T에서 U에 해당하는 멤버를 제거 합니다.
type AllColors = 'red' | 'green' | 'blue' | 'yellow';
// 'red'와 'blue'를 제거
type WarmColors = Exclude<AllColors, 'red' | 'blue'>;
// 'green' | 'yellow'
// 타입 종류로 필터링
type Mixed = string | number | boolean | null;
type OnlyPrimitives = Exclude<Mixed, null>;
// string | number | boolean
Exclude의 내부 구현
// 조건부 타입의 분배 법칙을 이용
type MyExclude<T, U> = T extends U ? never : T;
// 동작 원리 (유니온은 분배됨):
// Exclude<'a' | 'b' | 'c', 'a'>
// = ('a' extends 'a' ? never : 'a') | ('b' extends 'a' ? never : 'b') | ('c' extends 'a' ? never : 'c')
// = never | 'b' | 'c'
// = 'b' | 'c'
Extract<T, U> — 유니온에서 추출
T에서 U에 해당하는 멤버만 추출 합니다. Exclude의 반대입니다.
type AllColors = 'red' | 'green' | 'blue' | 'yellow';
// 'red'와 'blue'만 추출
type CoolColors = Extract<AllColors, 'red' | 'blue' | 'purple'>;
// 'red' | 'blue' (purple은 원래 없으므로 무시)
// 타입 종류로 추출
type Mixed = string | number | boolean | (() => void);
type OnlyFunctions = Extract<Mixed, Function>;
// () => void
Extract의 내부 구현
type MyExtract<T, U> = T extends U ? T : never;
NonNullable<T> — null과 undefined 제거
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>;
// string
// 복합 타입에서도 동작
type MaybeUser = { name: string } | null | undefined;
type DefiniteUser = NonNullable<MaybeUser>;
// { name: string }
NonNullable의 내부 구현
type MyNonNullable<T> = T & {};
// 또는
type MyNonNullable2<T> = T extends null | undefined ? never : T;
실전 활용 패턴
이벤트 타입 필터링
type Event =
| { type: 'click'; x: number; y: number }
| { type: 'keypress'; key: string }
| { type: 'scroll'; offset: number };
// 특정 이벤트 타입만 추출
type ClickEvent = Extract<Event, { type: 'click' }>;
// { type: 'click'; x: number; y: number }
type NonClickEvent = Exclude<Event, { type: 'click' }>;
// { type: 'keypress'; key: string } | { type: 'scroll'; offset: number }
객체 키 필터링
interface User {
id: number;
name: string;
email: string;
age: number;
isAdmin: boolean;
}
// string 타입인 키만 추출
type StringKeys = {
[K in keyof User]: User[K] extends string ? K : never;
}[keyof User];
// 'name' | 'email'
// 그 키들로 Pick
type StringFields = Pick<User, StringKeys>;
// { name: string; email: string }
함수 매개변수 필터링
// 특정 타입의 메서드만 추출
type MethodNames<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
}[keyof T];
class UserService {
name: string = '';
age: number = 0;
greet() { return 'hello'; }
getAge() { return this.age; }
}
type Methods = MethodNames<UserService>;
// 'greet' | 'getAge'
Exclude vs Omit 차이
공부하다 보니 이 둘을 혼동하는 경우가 많더라고요.
// Exclude — 유니온 멤버를 제거
type Colors = 'red' | 'green' | 'blue';
type WarmColors = Exclude<Colors, 'blue'>; // 'red' | 'green'
// Omit — 객체 속성을 제거
interface User { name: string; age: number; email: string; }
type WithoutEmail = Omit<User, 'email'>; // { name: string; age: number }
| Exclude | Omit | |
|---|---|---|
| 대상 | 유니온 멤버 | 객체 속성 |
| 동작 | 유니온에서 매칭되는 멤버 제거 | 객체에서 지정한 키 제거 |
정리
Exclude<T, U>: 유니온에서 U에 해당하는 멤버를 제거한다Extract<T, U>: 유니온에서 U에 해당하는 멤버만 추출한다NonNullable<T>: null과 undefined를 제거한다- 세 유틸리티 모두 조건부 타입의 분배 법칙으로 동작한다
- Exclude는 유니온 필터링, Omit은 객체 속성 제거 — 대상이 다르다
댓글 로딩 중...