infer란?

조민호·2023년 10월 27일
1

TypeScript의 infer 키워드는 조건부 타입에 사용되며, 조건식이 참으로 평가될 때 사용할 수 있는 타입을 추론하는 데 필요한 도구이다

이를 이용해 어떤 타입을 '찾아내고', 이 추론된 타입을 다른 타입과 함께 사용할 수 있다

number extends infer U

위와 같은 경우, U타입은 number타입으로 추론(infer)이 되는 것이며

이후에 참인 경우에 대응되는 식에서 추론한 U타입을 사용할 수 있다

infer 키워드는 주로 타입 변수가 들어갈 위치에서 사용된다

예를 들어, 배열의 요소들의 타입을 추론하고 싶을 때 다음과 같이 사용한다

type ArrayElement<T> = T extends (infer E)[] ? E : never;

type StringArray = string[];
type Element = ArrayElement<StringArray>;  // 'string'

간단히 말하면 아래와 같이 정의할 수 있다.

E 가 추론 가능한 타입이면 참, 아니면 거짓

  • T 자리에는 string타입 배열이 들어간다
  • T가 어떤 타입 E의 배열 (infer E)[]인지를 검사한다
  • 만약 TE 타입의 배열이라면, E를 반환한다 여기서 Einfer 키워드에 의해 추론된 타입인 string이다
  • 만약 TE 타입의 배열이 아니라면, never를 반환합니다

주의 사항

  1. infer 키워드는 extends와 함께 사용해야만 한다

    또한 extends 중에서

    • 제약 조건 extends가 아닌
    • 조건부 타입 extends절에서만 사용 가능하다
  2. 조건부 타입에서도 참일 경우에만 사용이 가능하다

    type ArrayElement<T> = T extends (infer E)[] ? any : E;

    위의 경우처럼 조건이 false인 경우에서는 infer로 추론된 타입을 사용할 수 없다


다른 예시로 , 함수의 반환 타입을 추론하는 예시를 들어 봅시다

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
  • ReturnType는 조건부 타입 이다
  • T가 함수 타입인지를 검사한다 만약 T가 함수 타입이라면, 그 함수의 반환 타입R (infer R) 이라고 정의하고 이 타입을 반환한다 여기서 Rinfer 키워드에 의해 추론된 함수의 반환 타입이다
  • 만약 T가 함수 타입이 아니라면, any를 반환한다

위의 타입을 아래와 같이 사용하는 것이다

type Func = () => number;

type Num = ReturnType<Func>;  // 'number'
  • Func 타입은 number를 반환하는 함수 타입이다
  • 그러므로 ReturnType의 제네릭으로 사용하게 되면 T 타입은 함수타입이므로 참이 되고, 그 함수의 반환 타입인 number가 R 로 추론이 되어 사용되는 것이다


((

(...args: any[]) 는 나머지 매개변수를 사용해서

모든 인자를 배열로 받고 , 이 배열에는 모든 타입이 가능하다는 것을

의미합니다

예시를 들어보면

function sum(...args: number[]): number[] {
  return args
}

console.log(sum(1, 2, 3));  // [1,2,3]
console.log(sum(1, 2, 3, 4, 5));  // [1,2,3,4,5]

sum 함수는 나머지 매개변수로 인해서 인자의 개수에 관계없이 모든 인자를 받을 수 있으며 , 모든 인자는 숫자형태여야 합니다

))




infer를 이용해서 프로미스의 타입을 파악하는 예시를 봅시다

TypeScript에서 Promise는 이 자체가 타입을 의미하는 것입니다

type PromiseType<T> = T extends Promise<infer U> ? U : never

type A = PromiseType<Promise<number>> // number

type B = PromiseType<Promise<string | boolean>> // string | boolean

type C = PromiseType<number> // never
  • 제네릭 T에 프로미스 타입을 넘겨줍니다
  • T가 만약 Promise 타입이라면 , 그 프로미스의 타입을 U 라고 정의하고 U 타입을 반환한다 여기서 U타입은 infer키워드에 의해 추론된 프로미스의 타입이다
  • T가 만약 Promise 타입이 아니라면 , never를 반환한다
type UnpackPromiseArray<P> = P extends Promise<infer K>[] ? K : any

const arr = [Promise.resolve(true)];

type ExpectedBoolean = UnpackPromiseArray<typeof arr> // boolean
  • arr 은 이행값으로 true를 가진 프로미스가 들어있는 배열이다
  • UnpackPromiseArray의 제네릭으로 arr을 넣어준다

    알다시피 arr은 타입이 아닌 변수이므로 반드시
    TS의 컴파일타임에 타입을 파악할 수 있도록 typeof와 같이 사용해야 한다
    그러므로 typeof arr 은 Promise[] 이 된다

  • 전달받은 P가 프로미스타입의 배열이라면 K를 반환한다 이때 K 는 infer 키워드에 의해 추론된 배열에 들어있는 프로미스의 타입이 된다
  • P가 프로미스타입의 배열이 아니라면 any 타입을 반환한다
profile
웰시코기발바닥

0개의 댓글