|
| 1 | +// TypeScript 타입 시스템에서 조건부 타입은 |
| 2 | +// 간단한 논리를 수행하는 방법을 제공합니다. |
| 3 | +// 확실히 고급 기능이며, |
| 4 | +// 일상 코드에서는 사용할 필요가 없을 것입니다. |
| 5 | + |
| 6 | +// A의 조건부 타입은 다음과 같습니다: |
| 7 | +// |
| 8 | +// A extends B ? C : D |
| 9 | +// |
| 10 | +// 조건은 타입이 표현식을 확장하는지 여부이며, |
| 11 | +// 만약 그렇다면 어떤 타입이 반환되어야 하는지입니다. |
| 12 | + |
| 13 | +// 몇 개의 예시를 살펴봅시다 |
| 14 | +// 간결함을 위해 제네릭에 단일 문자를 사용할 것입니다. |
| 15 | +// 선택 사항이지만 |
| 16 | +// 60자로 제한하면 화면에 맞추기 어렵습니다. |
| 17 | + |
| 18 | +type Cat = { meows: true }; |
| 19 | +type Dog = { barks: true }; |
| 20 | +type Cheetah = { meows: true; fast: true }; |
| 21 | +type Wolf = { barks: true; howls: true }; |
| 22 | + |
| 23 | +// barks 하는 것에 대해서만 일치하는 타입들을 추출하도록 해주는 |
| 24 | +// 조건부 타입을 만들 수 있습니다. |
| 25 | + |
| 26 | +type ExtractDogish<A> = A extends { barks: true } ? A : never; |
| 27 | + |
| 28 | +// 그러고 나서 ExtractDogish가 감싸는 타입을 만들 수 있습니다: |
| 29 | + |
| 30 | +// 고양이는 짖지 않는다고 하니, never를 반환합니다 |
| 31 | +type NeverCat = ExtractDogish<Cat>; |
| 32 | +// 늑대는 짖는다고 하니, 늑대 형태를 반환합니다 |
| 33 | +type Wolfish = ExtractDogish<Wolf>; |
| 34 | + |
| 35 | +// 많은 타입의 유니언을 사용하길 원하면서 |
| 36 | +// 유니언의 잠재적 선택사항의 개수를 |
| 37 | +// 줄이고 싶을 때 유용합니다: |
| 38 | + |
| 39 | +type Animals = Cat | Dog | Cheetah | Wolf; |
| 40 | + |
| 41 | +// ExtractDogish를 유니언 타입에 적용할 때 |
| 42 | +// 타입의 각 멤버와 비교하여 |
| 43 | +// 조건부를 실행하는 것과 같습니다: |
| 44 | + |
| 45 | +type Dogish = ExtractDogish<Animals>; |
| 46 | + |
| 47 | +// = ExtractDogish<Cat> | ExtractDogish<Dog> | |
| 48 | +// ExtractDogish<Cheetah> | ExtractDogish<Wolf> |
| 49 | +// |
| 50 | +// = never | Dog | never | Wolf |
| 51 | +// |
| 52 | +// = Dog | Wolf (예시를 살펴보세요:unknown-and-never) |
| 53 | + |
| 54 | +// 타입이 유니언의 각 멤버에 분배하기 때문에 |
| 55 | +// 분배 조건부 타입이라고 불립니다. |
| 56 | + |
| 57 | +// 지연된 조건부 타입 |
| 58 | + |
| 59 | +// 입력에 따라 다른 타입을 반환 할 수 있는 |
| 60 | +// 더 엄격한 API에 조건부 타입을 사용할 수 있습니다. |
| 61 | + |
| 62 | +// 예를 들어 이 함수는 입력받은 불린에 따라 |
| 63 | +// 문자열 또는 숫자를 반환 할 수 있습니다. |
| 64 | + |
| 65 | +declare function getID<T extends boolean>(fancy: T): T extends true ? string : number; |
| 66 | + |
| 67 | +// 그러고 나서 타입 시스템이 얼마나 많이 |
| 68 | +// 불린에 관해서 알고 있는지에 따라 다른 반환 타입을 얻습니다: |
| 69 | + |
| 70 | +let stringReturnValue = getID(true); |
| 71 | +let numberReturnValue = getID(false); |
| 72 | +let stringOrNumber = getID(Math.random() < 0.5); |
| 73 | + |
| 74 | +// 위의 사례에서 TypeScript는 반환 값을 즉시 알 수 있습니다. |
| 75 | +// 그러나, 타입이 아직 알려지지 않은 함수에서 |
| 76 | +// 조건부 타입을 사용 할 수 있습니다. |
| 77 | +// 이건 지연된 조건부 타입이라고 불립니다. |
| 78 | + |
| 79 | +// 위에 있던 Dogish와 같지만, 대신 함수입니다 |
| 80 | +declare function isCatish<T>(x: T): T extends { meows: true } ? T : undefined; |
| 81 | + |
| 82 | +// TypeScript에게 지연할 때 타입을 추론해야 한다고 |
| 83 | +// 구체적으로 알릴 수 있는 조건부 타입 내에 추가 유용한 도구가 있는데 |
| 84 | +// 바로 'infer' 키워드입니다. |
| 85 | + |
| 86 | +// infer는 일반적으로 |
| 87 | +// 코드에서 기존 타입을 검사하는 메타타입을 만드는 데 사용합니다 |
| 88 | +// infer를 타입 내부에서 새로운 변수를 만드는 것을 생각해 보세요. |
| 89 | + |
| 90 | +type GetReturnValue<T> = T extends (...args: any[]) => infer R ? R : T; |
| 91 | + |
| 92 | +// 대략적으로: |
| 93 | +// |
| 94 | +// - 첫 번째 매개변수에 있는 타입을 가진 |
| 95 | +// GetReturnValue 라는 조건부 제네릭 타입입니다. |
| 96 | +// |
| 97 | +// - 조건부는 타입이 함수인지 확인하고, |
| 98 | +// 만약 그렇다면 함수에 대한 반환 값을 기반으로 하여 |
| 99 | +// R이라는 새로운 타입을 만듭니다 |
| 100 | +// |
| 101 | +// - 검사를 통과하면, 타입 값은 추론된 반환 값이고 |
| 102 | +// 아니라면 원본 타입입니다 |
| 103 | +// |
| 104 | + |
| 105 | +type getIDReturn = GetReturnValue<typeof getID>; |
| 106 | + |
| 107 | +// 이것은 함수인지에 대한 검사를 실패하며, |
| 108 | +// 전달받은 타입을 반환할 수 있습니다. |
| 109 | +type getCat = GetReturnValue<Cat>; |
0 commit comments