TypeScript - 조건부 타입

안녕하세요, 미래의 TypeScript 마법사 여러분! 오늘 우리는 조건부 타입의 세계로 흥미로운 여정을 떠납니다. 프로그래밍에 처음 도전하는 분이라면 걱정하지 마세요. 저는 친절한 안내자가 되어 step-by-step로 함께할 테니까요. 이 수업이 끝나면 여러분이 배운 것을 깜빡이게 될 것입니다!

TypeScript - Conditional Types

기본 조건부 타입

먼저 기본부터 시작해보겠습니다. TypeScript의 조건부 타입은 코드에서 결정을 내리는 것과 같습니다. 얼음이 그 자리에 있는 상점에서巧克力和바닐라 중에서 선택해야 하는 상황을 상상해보세요. 그것이 TypeScript에서 조건부 타입이 하는 일입니다!

간단한 예제를 보겠습니다:

type IceCreamChoice = boolean extends true ? "Chocolate" : "Vanilla";

이 코드는 "boolean (true 또는 false를 나타냅니다)이 true일 수 있다면 Chocolate를 선택하고, 그렇지 않으면 Vanilla를 선택한다"고 말하고 있습니다.

하지만, boolean은 항상 true일 수 있잖아요? 그래서 더 실제적인 예제를 만들어보겠습니다:

type WeatherChoice<T> = T extends "Hot" ? "Ice Cream" : "Hot Chocolate";

let summerChoice: WeatherChoice<"Hot"> = "Ice Cream";
let winterChoice: WeatherChoice<"Cold"> = "Hot Chocolate";

여기서 우리는 WeatherChoice라는 타입을 만들어 T라는 타입 매개변수를 받습니다. T가 "Hot"를 확장하거나 일치하면 "Ice Cream"을 선택하고, 그렇지 않으면 "Hot Chocolate"를 선택합니다.

일반화된 조건부 타입

이제 레벨 업해보겠습니다! 일반화된 조건부 타입은 우리의 타입을 더 유연하고 재사용 가능하게 만듭니다. 이를 마치 초보적인 얼음이 그 자리에 있는 기계가 무엇을 넣는지에 따라 다양한 맛을 만들 수 있는 것처럼 생각해보세요.

type IsArray<T> = T extends any[] ? true : false;

type CheckString = IsArray<string>;  // false
type CheckNumberArray = IsArray<number[]>;  // true

이 예제에서 IsArray는 입력 타입 T가 배열인지 확인하는 일반화된 타입입니다. 배열이라면 true를 반환하고, 그렇지 않으면 false를 반환합니다.

여기서 더 복잡한 예제를 시도해보겠습니다:

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

type StringArrayElement = ElementType<string[]>;  // string
type NumberArrayElement = ElementType<number[]>;  // number
type NotArrayElement = ElementType<number>;  // never

여기서 ElementType는 배열의 요소 타입을 추출합니다. T가 배열이라면 요소 타입 U를 추론하고 반환하고, 그렇지 않으면 never를 반환합니다.

조건부 타입 제약

occasionally, we want to put some restrictions on our types. It's like saying, "You can only have ice cream if you've finished your vegetables!" Let's see how this works in TypeScript:

type NumberOperation<T extends number> = T extends 0 ? "Zero" : "Non-zero";

type ZeroCheck = NumberOperation<0>;  // "Zero"
type NonZeroCheck = NumberOperation<5>;  // "Non-zero"
type InvalidCheck = NumberOperation<"5">;  // Error: Type '"5"' does not satisfy the constraint 'number'.

이 예제에서 NumberOperationnumber를 확장하는 타입만 받습니다. 그런 다음, 숫자가 0인지 아닌지 확인합니다.

조건부 타입 내에서 추론

마지막으로, 조건부 타입 내에서 추론에 대해 이야기해보겠습니다. 이는 마치 초보적인 얼음이 그 자리에 있는 기계가 당신의 기분에 따라 원하는 맛을 알아내는 것처럼입니다!

type Flatten<T> = T extends Array<infer U> ? U : T;

type FlattenedNumberArray = Flatten<number[]>;  // number
type FlattenedString = Flatten<string>;  // string

여기서 FlattenT가 배열인지 확인합니다. 배열이라면 요소 타입 U를 추론하고 반환하고, 그렇지 않으면 T를 그대로 반환합니다.

여기서 더 고급스러운 예제를 시도해보겠습니다:

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

function greet(name: string): string {
return `Hello, ${name}!`;
}

type GreetReturn = ReturnType<typeof greet>;  // string

이 예제에서 ReturnType은 함수의 반환 타입을 추론합니다. T가 함수 타입이라면 반환 타입 R을 추론하고 반환합니다.

결론

축하합니다! TypeScript의 조건부 타입의 세계로 첫 걸음을 뗐습니다. 자전거 타는 것을 배우는 것처럼,처음에는 흔들릴 수 있지만, 연습을 거듭하면 곧 빠르게 탈 수 있을 것입니다!

여기서 다루었던 방법들의 빠른 참고 표를 제공합니다:

방법 설명
기본 조건부 타입 조건에 따라 타입을 결정합니다
일반화된 조건부 타입 유연하고 재사용 가능한 조건부 타입을 만듭니다
조건부 타입 제약 입력 타입에 제약을 두습니다
조건부 타입 내에서 추론 조건 내에서 타입을 추론합니다

계속 연습하고, 호기심을 유지하면, 곧 TypeScript로 놀라운 것을 만들 수 있을 것입니다. 행복하게 코딩하세요, 미래의 TypeScript 마스터 여러분!

Credits: Image by storyset