TypeScript에서 고차형 타입을 모방하는 실용적인 방법
TypeScript는 고차형 타입(HKT)을 기본적으로 지원하지 않아, Array, Set, Promise와 같은 타입 생성자 위에서 재사용 가능한 추상화를 만들 수 있는 데 제한이 있습니다. 고차형 타입은 요소 타입뿐만 아니라 컨테이너 자체까지 매개변수화할 수 있게 해주며, 함수형 패턴인 포인터(functor)와 모나드(monad)의 강력한 타입 안정성을 제공합니다. 이 기능이 없으면 각 데이터 타입마다 map과 같은 연산을 반복 구현해야 합니다.
예를 들어, Set에 대해 map을 구현하는 작업을 생각해 봅시다.
type MapSet = <A, B>(f: (a: A) => B, set: Set<A>) => Set<B>;
비슷하게 ReadonlySet, LinkedList, ReadonlyArray에도 각각 별도의 버전이 필요합니다. 고차형 타입이 없다면 중복 코드를 피할 수 없습니다. 하지만 HKT가 있다면 단순히 Mappable<F> 인터페이스로 F<A> → F<B> 형태의 시그니처를 정의할 수 있습니다.
TypeScript는 Type ‘F’ is not generic라는 오류를 발생시키는데, 이는 타입 종류(: 문자열)와 → *: 배열처럼 타입 생성자의 차이를 구분하지 못하기 때문입니다.
생성자 사전을 통한 모방
가장 간단한 대안은 문자열 키를 타입으로 매핑하는 사전 방식입니다.
interface TypeConstructors<A> {
'Array': Array<A>;
'LinkedList': LinkedList<A>;
'ReadonlySet': ReadonlySet<A>;
'Set': Set<A>;
}
type Kind<F extends keyof TypeConstructors<unknown>, A> = TypeConstructors<A>[F];
Kind<'Array', number>는 Array<number>로 확장됩니다. 이 기반 위에서 일반화된 타입을 구성할 수 있습니다:
type Mappable<F extends keyof TypeConstructors<unknown>> = <A, B>(
f: (a: A) => B,
list: Kind<F, A>
) => Kind<F, B>;
구체적인 타입에 대한 구현 예시:
const mapArray: Mappable<'Array'> = (f, list) => list.map(f);
const mapSet: Mappable<'Set'> = (f, list) => new Set(Array.from(list, f));
아리티 제한과 해결책
이 접근법은 단항 생성자( → )에는 잘 작동하지만, 이항 생성자인 Map<K, V>처럼 다중 매개변수를 받는 경우 별도의 사전이 필요합니다.
interface TypeConstructors2<A, B> {
Map: Map<A, B>;
Record: Record<A, B>;
}
type Kind2<F extends keyof TypeConstructors2<unknown, unknown>, A, B> = TypeConstructors2<A, B>[F];
다양한 아리티를 처리하는 것은 복잡해지며, 실제 프로젝트에서는 다음과 같은 라이브러리를 활용합니다:
- hkt-toolbelt: 최대 4개의 매개변수를 지원하며, 포인터와 모나드를 위한 유틸리티 포함.
- hkt-core: 타입 성능에 집중하고, 최소한의 API 표면적을 제공.
이 도구들은 실제 고차형 타입에 가까운 타입 추론을 제공하여 수동으로 사전을 관리할 필요 없게 만듭니다.
고차형 타입 채택의 주요 과제
2026년 기준으로도 고차형 타입은 여전히 추가되지 않았으며, 지속적인 요청(이슈 #1213, #55280)에도 불구하고 주요 장벽은 다음과 같습니다:
- 컴파일러 복잡성: 종류 다형성(kind polymorphism) 도입, 타입 추론 확장, 구조적 타이핑 적응.
- 성능 문제: 대규모 함수형 프로젝트에서 컴파일 시간 증가.
- 설계적 트레이드오프: 표현력과 자바스크립트 호환성 간 균형, 문법 부담 회피.
제안된 해결책:
- 타입 생성자를 위한 특수 마커(
F<~>). - 새로운 문법 없이 조건부 타입 개선.
- 기존 TypeScript 기능을 활용한 실용적인 모방.
가장 중요한 점
- 고차형 타입은 종류 매핑을 통해 컨테이너의 엄격한 타입 보존이 가능합니다.
hkt-toolbelt및hkt-core와 같은 라이브러리는 중급 이상 프로젝트에서 통합을 간편하게 만듭니다.- 아리티는 별도의 사전이 필요하며, 단항 타입은 기초 사용 사례에 이상적입니다.
- 미래의 네이티브 지원은 성능을 희생하지 않는 점진적 개선을 통해 가능할 수 있습니다.
- 모방을 통해
Array,Set,Promise등 다양한 타입에서map,flatMap등의 함수를 중복 없이 깔끔하게 구현할 수 있습니다.
— Editorial Team
아직 댓글이 없습니다.