본문 바로가기
C.W.K.
Stream
Lesson 07 of 07 · published

infer: 타입의 모양에서 필요한 조각 꺼내기

~11 min · generics, infer, conditional-types, type-extraction

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"infer는 조건부 타입의 패턴 안에서 ‘이 자리에 있던 타입을 이름 붙여 줘’라고 말해."

타입 수준의 구조 분해

T extends Array<infer E> ? E : never는 T가 배열 모양인지 확인하고, 맞다면 원소 자리에 있던 타입을 E라는 이름으로 붙잡아 결과로 돌려줘. 값의 구조 분해처럼 타입의 모양에서 필요한 조각을 꺼내는 기능이야.

infer는 조건부 타입의 extends 패턴 안에서만 사용할 수 있어. 독립적으로 새 타입 변수를 선언하는 문법이 아니라 ‘이 패턴이 맞을 때 이 부분을 추론하라’는 표시야.

자주 쓰는 네 패턴

배열의 원소는 T extends (infer E)[], 함수의 반환값은 F extends (...args: any[]) => infer R, Promise가 풀어 낸 값은 T extends Promise<infer V>, 함수의 전체 매개변수는 F extends (...args: infer P)로 꺼낼 수 있어.

ReturnType, Parameters, Awaited 같은 표준 유틸리티가 이미 이 일을 해 주므로 앱 코드에서 직접 다시 만들 필요는 적어. 하지만 문법을 읽을 수 있어야 라이브러리 정의가 무엇을 계산하는지 이해할 수 있다.

FirstArg<F>처럼 함수의 첫 매개변수 자리에 infer A를 놓아 타입을 꺼낼 수 있어. infer가 없으면 ‘이 모양인가?’라는 yes/no 검사만 가능하지만, infer가 있으면 맞은 모양 안의 타입을 새 이름에 묶어 참 분기에서 사용할 수 있어.

조건부 타입이 ‘이 모양인가’를 묻는다면 infer는 ‘그 안의 이 조각은 무엇인가’를 답해.

Code

Canonical infer 패턴 4개·typescript
// Canonical 4개 `infer` 패턴.

// 1. 배열의 element.
type ElementOf<T> = T extends (infer E)[] ? E : never;
type A = ElementOf<string[]>;        // string
type B = ElementOf<User[]>;          // User

// 2. 함수의 return 타입.
type ReturnOf<F> = F extends (...a: any[]) => infer R ? R : never;
type C = ReturnOf<() => string>;     // string
type D = ReturnOf<typeof JSON.parse>;// any (JSON.parse 가 any 반환)

// 3. Promise unwrap.
type Unwrap<T> = T extends Promise<infer V> ? V : T;
type E = Unwrap<Promise<User>>;      // User
type F = Unwrap<User>;               // User (non-Promise 통과)

// 4. 함수의 첫 argument.
type FirstArg<F> = F extends (first: infer A, ...rest: any[]) => any ? A : never;
type G = FirstArg<(x: number, y: string) => void>;  // number

External links

Exercise

함수 타입의 모든 매개변수를 튜플로 꺼내는 ParametersOf<F>를 작성해. infer가 나머지 매개변수 전체를 한 타입 변수로 잡게 해.
Hint
type ParametersOf<F> = F extends (...args: infer P) => any ? P : never처럼 나머지 매개변수 전체를 P라는 튜플로 잡아.

Progress

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

댓글 0

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

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