타입스크립트 infer 키워드 완벽 정복 가이드

타입스크립트 infer 키워드 완벽 정복 가이드

타입스크립트에서 infer 키워드는 조건부 타입 안에서 타입을 추론할 때 사용됩니다.

 

복잡한 타입을 다룰을 때 특히 유용하며, 타입을 추출하거나 변환할 수 있게 해준죠.

 

1. 기본 사용법

 

infer 키워드는 조건부 타입 안에서만 사용할 수 있으며, 보통 제네릭과 extends 키워드와 함께 사용됩니다. 문법은 다음과 같습니다.

type Moment<T> = T extends infer U ? U : never;

 

여기서 T extends infer U는 T 타입을 추론하여 U에 할당하려고 시도한다는 의미입니다.

 

타입 추론이 성공하면 U는 추론된 타입이 됩니다.

 

다양한 타입을 추론하는 데 사용할 수 있습니다. 몇 가지 예시를 들어보겠습니다.

type Moment<T> = T extends infer U ? U : never;

type StringType = Moment<string>; // string
type NumberType = Moment<number>; // number
type UnionType = Moment<string | number>; // string | number

interface User {
  name: string;
  age: number;
}

type UserType = Moment<User>; // User

 

이 예시에서 Moment는 기본적으로 변환이나 처리 없이 타입 T를 반환합니다.

 

이는 주로 조건부 타입과 타입 추론의 기본 사용법을 보여주기 위한 것입니다.

 

2. 일반적인 예시

 

함수의 반환 타입 추출하기

 

함수 타입이 있고 그 반환 타입을 추출하고 싶다고 가정해봅시다.

 

다음과 같이 할 수 있습니다.

type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

type ExampleFunction = (x: number, y: string) => boolean;
type ReturnTypeOfExampleFunction = GetReturnType<ExampleFunction>; // boolean

 

위 코드에서:

  • T extends (...args: any[]) => infer R: T가 함수 타입인지 확인합니다. (...args: any[])는 함수가 어떤 수의 인수를 받아들일 수 있음을 의미합니다.
  • infer R: T가 함수 타입이면 infer R은 함수의 반환 타입을 추론하여 타입 변수 R에 할당합니다.
  • ? R : never: T가 함수 타입이면 추론된 반환 타입 R을 반환하고, 그렇지 않으면 never를 반환합니다.

배열의 요소 타입 추출하기

 

infer를 사용하여 배열의 요소 타입도 추출할 수 있습니다.

type GetArrayElementType<T> = T extends (infer U)[] ? U : never;

type Moment = string[];
type Example1Array = Array<string>;

type ElementTypeOfExampleArray = GetArrayElementType<Moment>; // string
type ElementTypeOfExample1Array = GetArrayElementType<Example1Array>; // string

 

여기서 T extends (infer U)[]를 사용하여 배열의 요소 타입 U를 추론합니다.

 

T가 string[]이므로 U는 string이 됩니다.

 

중요 참고: infer 선언은 조건부 타입의 extends 절 안에서만 허용되며, infer로 선언된 타입 변수는 true 분기 안에서만 사용할 수 있습니다.

 

3. 고급 예시

 

프로미스의 값 타입 추출하기

 

프로미스 타입이 있으면 그 해결된 값 타입을 추출할 수 있습니다.

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

// 예시
type ExamplePromise = Promise<number>;
type ValueTypeOfExamplePromise = GetPromiseValueType<ExamplePromise>; // number

 

위 코드에서:

  • T extends Promise<infer U>: T가 프로미스 타입인지 확인합니다.
  • infer U: T가 프로미스 타입이면 infer U는 프로미스의 해결된 값 타입을 추론하여 U에 할당합니다.
  • ? U : never: T가 프로미스 타입이면 추론된 값 타입 U를 반환하고, 그렇지 않으면 never를 반환합니다.

함수의 매개변수 타입 추출하기

 

때때로 함수의 매개변수 타입을 얻어야 할 때가 있습니다.

 

infer를 사용하여 이를 달성할 수 있습니다.

type GetParameters<T> = T extends (...args: infer P) => any ? P : never;

type ExampleFunction = (a: number, b: string) => void;
type Params = GetParameters<ExampleFunction>; // [number, string]

 

위 코드에서:

  • T extends (...args: infer P) => any: T가 함수 타입인지 확인합니다.
  • infer P: T가 함수 타입이면 infer P는 함수의 매개변수 타입을 추론하여 P에 할당합니다.
  • ? P : never: T가 함수 타입이면 추론된 매개변수 타입 P를 반환하고, 그렇지 않으면 never를 반환합니다.

생성자 매개변수 타입 추출하기

 

infer를 사용하여 클래스 생성자의 매개변수 타입도 추출할 수 있습니다.

type ConstructorParameters<T> = T extends new (...args: infer P) => any ? P : never;

class ExampleClass {
  constructor(public a: number, public b: string) {}
}

type Params = ConstructorParameters<typeof ExampleClass>; // [number, string]

 

4. 조건부 타입에서의 복잡한 추론

 

조건부 타입 안에서 복잡한 추론 로직을 사용해야 할 때가 있습니다.

type IsArray<T> = T extends (infer U)[] ? U : never;
type IsFunction<T> = T extends (...args: any[]) => infer R ? R : never;

type ExtractType<T> = T extends any[]
  ? IsArray<T>
  : T extends (...args: any[]) => any
  ? IsFunction<T>
  : T;

// 예시
type ArrayType = ExtractType<string[]>; // string
type FunctionReturnType = ExtractType<() => number>; // number
type DefaultType = ExtractType<boolean>; // boolean

 

위 코드에서:

  • T extends any[] ? IsArray<T>: T가 배열 타입이면 IsArray를 반환하여 배열의 요소 타입을 추출합니다.
  • T extends (...args: any[]) => any ? IsFunction<T>: T가 함수 타입이면 IsFunction을 반환하여 함수의 반환 타입을 추출합니다.
  • T: T가 배열 타입도 함수 타입도 아니면 T 자체를 반환합니다.

요약

 

타입스크립트에서 infer 키워드는 조건부 타입 안에서 다른 타입으로부터 새로운 타입 변수를 추론할 때 사용됩니다.

 

타입 검사 중에 특정 하위 타입이나 속성을 추출하고 활용할 수 있게 해주어 타입스크립트의 타입 시스템의 표현력과 유연성을 향상시킵니다.

 

간단히 말해, infer는 복잡한 타입에서 원하는 부분을 자동으로 추출하는 데 도움을 줍니다.