# 조건부타입 (Conditional types)

> [타입스크립트 핸드북을 참고하자.](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html)

### 삼항연산자와 비슷하다

조건에 의한 타입결정은 일반 프로그래밍 언어의 **삼항연산자와 비슷하다.** 아래의 형태로 사용한다.

```typescript
 SomeType extends OtherType ? TrueType : FalseType;
```

만약 `SomeType` 이 `OtherType` 에 `assignable` 하다면, `TrueType` 이 되고 아니라면 `FalseType` 이 된다.

### 제한을 걸어보자

`message` 라는 `prop` 을 가지고 있는 타입에서 해당 `message` 타입을 가져오는 경우를 생각해보자.

```typescript
type MessageOf<T> = T["message"]; // 에러 발생
```

이 코드에서 에러가 나오는 이유는 `T` 라는 타입에 `message` 의 존재여부를 알지 못하기 때문이다. 여기서 우리는 **Constraints 를 만듦으로써 에러를 해결할 수 있다.**

```typescript
type MessageOf<T extends { message: unknown }> = T["message"]
```

앞에 제한을 넣음으로써 빨간줄은 해결했다. 다만 이렇게 만들면 **사용성이 떨어진다.** 왜? 사용에 있어 무조건 `message` 라는 프롭이 있어야지만 실행이 되기 때문이다. 따라서 이번에는 `message` 가 없으면 `never` 를 나오게 수정해보자.

```typescript
type MessageOf<T> = T extends { message: unknown } ? T["message"] : never
```

### 추론을 알아보자

이번에는 `Array` 를 Flatten 하게 만드는 조건부타입을 만들어보자. 만약 `string[]` 라는 타입을 `string` 으로 `Flatten` 하고 싶다면 아래처럼하면된다.

```
type Flatten<T> = T extends unknown[] ? T[number] : T;
```

이렇게 해도 되지만 지금 문제는 `T[number]` 처럼 `indexed Access Types` 를 사용한다는 것이다. ([Indexed Access Types 가 뭐야?](https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html))

이렇게 직접적으로 접근하는 방법보다 더 좋은 방법이 있는데 바로 **내부 타입을 타입스크립트한테 추론을 맡기는 것이다.** 추론을 맡기는 방법은 굉장히 직관적이고 쉽다. 바로 `infer` 키워드를 사용하는 것. `infer` 키워드를 사용해서 개선해보자.

```typescript
type Flatten<T> = T exnteds Array<infer R> ? R : T;
```

`infer` 를 이용해서 `Return` 타입을 동적으로 결정하는 타입을 만들어보자.

```typescript
type GetReturnType<t> = T extends ( ...args: never[]) => infer Return ? Return : never
```

### Distribute Conditional Types

> 분배 조건 타입

이름이 뭔가 이상해보이는데, 요지는 간단하다. **유니온 타입으로 들어온 타입들에 대해서, 하나하나 적용해 나간다는 의미다.** 예시를 보자.

```typescript
type ToArray<T> = T extends any ? T[] | never;
```

`T` 로 들어온 타입을 배열로 만들어주는 `ToArray`가 있다. 위에서 이야기한 대로 `T` 에 유니언타입을 넣으면 어떻게 될까?

```typescript
// ToArray 의 타입인자로 string | number 을 넣어줌
type StrArrOrNumArr = ToArray<string | number>;

// 결과
type StrArrOrNumArr = string[] | number[]
```

자 대체 왜 `StrArrOrNumArr` 는 `string[] | number[]` 가 되었을까? 이유는 간단하다. `union` 들이 반복문을 돌면서 하나하나 들어갔기 때문이다!!

만약 반복을 돌기 싫고 `(string | number)[]` 과 같은 결과를 얻고 싶다면 `()` 를 잘 사용해주면된다.

```typescript
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;

// 'StrArrOrNumArr' is no longer a union.
type StrArrOrNumArr = ToArrayNonDist<string | number>;
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://simian114.gitbook.io/blog/undefined/undefined-3/conditional-types.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
