0Pricing
TypeScript Academy · 강의

TypeScript의 HKT 문제

제네릭 타입 생성자가 어려운 이유를 이해합니다.

TypeScript의 HKT 문제은(는) CoddyKit의 무료 TypeScript Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 TypeScript Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. TypeScript Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

고차 타입이란

고차 타입(HKT)은 구체적인 타입이 아니라 타입 생성자를 추상화합니다. 타입 생성자는 Array나 Promise처럼 실제 타입이 되려면 인수가 필요한 대상입니다.

Array만으로는 타입이 아닙니다. Array<string>은 타입입니다. Array는 타입에 작용하는 함수이며, HKT를 사용하면 이러한 함수에 대해서도 제네릭하게 작성할 수 있습니다.

type StringArray = Array<string>;
type NumberArray = Array<number>;
// Array by itself is a type constructor, not a type

종류를 간단히 살펴보기

값에 타입이 있는 것처럼 타입 생성자에는 종류가 있습니다. number와 같은 일반 타입의 종류는 *입니다. Array의 종류는 * -> *입니다. 타입 하나를 주면 타입 하나를 반환합니다. 이러한 대상에 대해 제네릭하게 작성하는 것을 "고차"라고 합니다.

type ValueLike = number;        // kind *
// Array needs one argument:    kind * -> *
// Map needs two arguments:     kind * -> * -> *

목표: Functor<F>

HKT를 지원하는 언어에서는 배열, 옵션, 프로미스 등 어떤 컨테이너 F에도 작동하는 map 하나를 포함한 Functor<F> 추상화를 작성할 수 있습니다. 하나의 인터페이스로 여러 컨테이너를 다룰 수 있습니다.

interface Wish_Functor<F> {
  map<A, B>(fa: F<A>, f: (a: A) => B): F<B>;
}
// F<A> here is the wish - and TypeScript rejects it

문제

TypeScript는 타입 매개변수를 인수에 적용하는 기능을 지원하지 않습니다. F가 제네릭 매개변수일 때는 F<A>를 작성할 수 없습니다. 컴파일러는 "F 타입은 제네릭이 아닙니다"라는 오류를 표시합니다.

// interface Functor<F> {
//   map<A, B>(fa: F<A>, f: (a: A) => B): F<B>;
// }
// Error: Type F is not generic

TS에 이 기능이 없는 이유

TypeScript의 타입 매개변수는 1차 매개변수입니다. 타입 생성자가 아니라 구체적인 타입을 대상으로 합니다. "F가 타입 인수 하나를 받는 대상"이라고 표현할 문법이 없습니다. 따라서 F<A>는 컴파일러에게 의미가 없습니다.

// You can pass number, string, User as F...
// but not Array, not Promise (the constructors themselves)

구체적인 문제 지점

HKT가 없으면 모든 컨테이너에 대해 map을 중복해서 작성해야 합니다. 배열용 하나, 옵션용 하나, 프라미스용 하나가 필요합니다. 논리는 동일하지만 타입 시스템이 이들을 하나로 통합하지 못합니다.

declare function mapArray<A, B>(fa: A[], f: (a: A) => B): B[];
declare function mapOption<A, B>(fa: A | null, f: (a: A) => B): B | null;
// Same shape, but no way to abstract over the container

표현하고 싶은 것

하나의 시그니처를 원합니다. A의 컨테이너와 A -> B 함수를 받으면 B의 컨테이너를 반환하되, 컨테이너 타입은 유지하는 것입니다. 배열은 배열로, 옵션은 옵션으로 남아야 합니다.

// Wish: map<F, A, B>(fa: F<A>, f: (a: A) => B): F<B>
// where F is preserved across the call

다른 언어에서는

Haskell과 Scala에는 HKT가 기본적으로 제공되므로 Functor, Applicative, Monad 같은 타입 클래스를 그곳에서는 표현할 수 있습니다. TypeScript에서는 같은 수준의 기능을 근사하기 위한 우회 방법이 필요합니다.

// Haskell: class Functor f where fmap :: (a -> b) -> f a -> f b
// TypeScript: needs an encoding trick (next lessons)

인코딩의 발상

표준적인 우회 방법은 함수화 제거입니다. F를 직접 적용하는 대신 각 컨테이너에 문자열 태그(URI)를 부여하고, 태그와 인수를 구체적인 타입에 매핑하는 레지스트리를 유지합니다. 타입 적용이 조회로 바뀌는 것입니다.

// Instead of F<A>, we write Kind<F, A> where F is a URI string
// and a registry resolves it to the real type

만들게 될 것

다음 수업들에서는 fp-ts 스타일의 HKT 인코딩을 단계별로 구축합니다. URItoKind 레지스트리, Kind 조회, 그리고 등록된 모든 컨테이너에서 작동하는 제네릭 Functor와 그 map을 차례로 작성합니다.

// Roadmap:
// 1. Type constructors via URI strings
// 2. Kind<F, A> resolution
// 3. Generic Functor + instances

알아 둘 가치가 있는 이유

이 인코딩을 직접 작성하는 경우는 드물지만, fp-ts와 Effect 같은 라이브러리는 이를 기반으로 합니다. 이 기법을 이해하면 해당 라이브러리의 타입을 읽고, 컨테이너에 대한 제네릭 추상화를 작성하며, 타입 시스템이 할 수 있는 일과 할 수 없는 일을 더 잘 이해할 수 있습니다.

// Recognizing Kind<F, A> in library code is the payoff

빠른 확인

HKT 문제에 대한 이해도를 확인해 보십시오.

복습

고차 타입 문제를 살펴보았습니다.

  • HKT는 구체적인 타입이 아니라 Array 같은 타입 생성자를 추상화합니다.
  • TypeScript의 타입 매개변수는 1차이므로 F<A>는 사용할 수 없습니다.
  • 이 때문에 하나의 map을 가진 단일 제네릭 Functor를 작성할 수 없습니다.
  • 해결책은 URI 태그와 레지스트리를 사용하는 인코딩입니다.

다음: URI 문자열로 타입 생성자 정의하기

자주 묻는 질문

“TypeScript의 HKT 문제” 강의는 무료인가요?

네 — “TypeScript의 HKT 문제” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 TypeScript Academy 강의 전체를 잠금 해제할 수 있습니다. TypeScript Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“TypeScript의 HKT 문제”에서 뭘 배우나요?

제네릭 타입 생성자가 어려운 이유를 이해합니다. 브라우저에서 직접 실행하는 실습 코드로 TypeScript Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

TypeScript Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 TypeScript Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“TypeScript의 HKT 문제” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 TypeScript Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 TypeScript Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. TypeScript의 HKT 문제
  2. 타입 생성자 정의
  3. 경량 HKT 패턴
  4. 제네릭 펑터와 매퍼
← TypeScript Academy(으)로 돌아가기