"바뀌는 필드 하나만 타입 매개변수로 들어 올리면, 거의 같은 모양 여러 개가 하나의 계약으로 모여."
타입에 빈칸을 둬
interface Box<T> { value: T }는 어떤 값이든 담는 상자 모양을 한 번 정의해. Box<string>은 문자열 상자, Box<User>는 사용자 상자야. type 별칭도 같은 방식으로 타입 매개변수를 받을 수 있어.
제네릭 타입을 구체화하면 빈칸이 실제 타입으로 치환되고, 그 결과가 평범한 타입처럼 다른 계약 안에 다시 들어갈 수 있어. Promise<PaginatedResponse<User>>처럼 여러 층을 조합해도 원리는 같다.
컨테이너뿐 아니라 결과와 동작도
Result<T, E>는 성공 값 T와 실패 값 E를 가진 판별 가능한 유니언을 만들 수 있어. Reducer<State, Action>은 상태와 행동 사이의 함수 관계를 이름 붙인다. 제네릭은 자료 구조에만 쓰는 기능이 아니라 반복되는 타입 관계의 틀이야.
거의 같은 타입을 복사하지 마
UserResponse, PostResponse, CommentResponse가 items 필드의 원소만 다르고 나머지 pagination 정보가 같다면 각 타입을 손으로 만들 이유가 없어. PaginatedResponse<T> 하나가 관계를 보존하고 공통 구조의 변경도 한곳에서 처리하게 해.
제네릭 별칭과 인터페이스 모두 Pair<T, U> 같은 타입 슬롯을 가질 수 있어. 표준 라이브러리의 Array<T>, Promise<T>, Map<K, V>, Set<T>도 같은 구조야. 컨테이너뿐 아니라 Result<T, E>나 EventHandler<T>처럼 결과와 동작의 관계에도 쓸 수 있어.