# 5.3 함수 타입의 호환성

### 매개변수 수가 같은 경우

함수 타입 간의 호환성을 판단하려 할 때, 가장 간단한 경우는 두 함수의 매개변수의 갯수가 같은 경우다. 이 때, 할당을 받는 함수의 타입을 `Target`, 할당하려는 함수의 타입을 `Source`라 하자.

```typescript
let source: Source;
const target: Target = source;
```

위 코드가 허용되는지, 즉 `Target`이 `Source`에 할당 가능한지를 보기 위해선 다음 두 질문에 답해야 한다.

* `Target`과 `Source`의 모든 매개변수 타입에 대해, `Source`의 매개변수 타입이 `Target`의 매개변수 타입에 할당 가능한가?
* `Target`의 반환 타입이 `Source`의 반환 타입에 할당 가능한가?

두 질문에 대한 답이 모두 “예”라면, `Target`은 `Source`에 할당 가능하다.&#x20;

{% hint style="info" %}
직관적으로는, 선택 매개변수와 필수 매개변수는 호환성을 판단할 때 다르게 취급되는 게 맞아 보인다. 하지만 타입스크립트에선 매개변수가 선택 매개변수인지 필수 매개변수인지는 함수 타입의 호환성 판단에 아무런 영향을 주지 않는다.
{% endhint %}

#### **할당 가능한 경우**

먼저 할당 가능한 경우를 살펴보자.

```typescript
type Sum = (sumFirst: number, sumSecond: number) => number;
type Multiply = (mulFirst: number, mulSecond: number) => number;
```

* 모든 매개변수 타입은 `number`로, 서로 할당 가능하다.
* `Multiply`의 반환 타입인 `number`는 `Sum`의 반환 타입인 `number`에 할당 가능하다.

따라서 `Sum`은 `Multiply`에 할당 가능하다.

```typescript
const sum: Sum (sumFirst: number, sumSecond: number) => {
  return sumFirst + sumSecond;
};
const multiply: Multiply = sum; // ok
```

#### **할당 불가능한 경우**

다음으로는 할당이 불가능한 예제를 살펴보자.

```typescript
interface Animal { animalProp: string };
interface Dog extends Animal { dogProp: number };

let f = (animal: Animal) => animal.animalProp;
let g = (dog: Dog) => { doSomething(dog.dogProp) };

f = g;
```

* 할당받는 함수의 매개변수 타입 `Animal`은 할당하는 함수의 매개변수 타입 `Dog`에 할당 불가능하다.&#x20;

만족되지 않는 기준이 있으므로 `g`는 `f`에 할당할 수 없다.&#x20;

{% hint style="info" %}
이 때, 이 기준을 만족해야 하는 이유는 뭘까? 즉, `f`의 매개변수 타입인 `Animal` 이 `g`의 매개변수 타입인 `Dog`에 할당 불가능하면 왜 `g`를 `f`에 할당하지 못해야 할까?

해당 할당을 허용하는 경우를 생각해보자. 만약 `f = g` 의 할당을 허용한다면 다음과 같이 `Animal` 타입의 인자를 넘길 수 있을 것이다.

```typescript
const cat: Animal = { animalProp: 'cute' };
f(cat); // 컴파일러는 통과 시켜 줌
```

하지만 `g` 는 인자가 `Dog` 일 것이라 가정하고, `Dog` 에만 존재하는 속성 `dogProp` 에 접근하고 있다. 따라서 런타임 에러가 발생할 수 있다. 이런 상황을 막기 위해 타입스크립트는 이 경우 `f = g` 와 같은 할당을 금지한다.
{% endhint %}

### **매개변수 수가 다른 경우**

매개변수 수가 같은 두 함수의 호환성을 비교하는 법에 대해 살펴봤다. 이번엔 매개변수의 수가 다른 경우엔 상황이 어떻게 달라지는지를 다음 두 함수 타입을 통해 살펴보자.

```typescript
type Login = (id: string) => Response<Data>;
type LoginWithToken = (id: string, token: string) => Response<Data>;
```

#### **할당하는 함수의 매개변수 수가 더 많은 경우**

아래 코드에서 할당하는 함수인 `loginWithToken`은 할당받는 함수 `login`에 비해 `token: string` 이라는 매개변수를 추가적으로 갖고 있다.&#x20;

```typescript
const loginWithToken: LoginWithToken = (id: string, token: string) => { /* ... */ };
const login: Login = loginWithToken;
```

이런 경우는 할당이 **불가능**하다. 만약 이 할당을 허용한다고 생각해보자. 프로그래머는 이 함수를 다음과 같은 식으로 호출할 것이다.

```typescript
login('myId');
```

이는 `loginWithToken` 함수를 `token` 인자 없이 호출하는 셈이다. `loginWithToken` 함수 내에서 `token`을 `string` 타입이라 생각하고 사용했다면, `string`이 필요한 자리에 `undefined` 값이 넘어와서 런타임 에러가 발생할 것이다. 따라서 이런 할당은 허용되지 않는다.

#### **할당받는 함수의 매개변수 수가 더 많은 경우**

아래 코드에서 할당하는 함수인 `login`은 할당받는 함수인 `loginWithToken`에 비해 매개변수 수가 하나 모자라다.&#x20;

```typescript
const login: Login = (id: string) => { /* ... */ };
const loginWithToken: LoginWithToken = login;
```

이런 경우, **초과 매개변수는 무시된다**. 그리고 매개변수 수가 같을 때와 동일한 알고리즘으로 호환성을 판단한다. 위의 경우, 초과 매개변수인 `token: string` 을 제외하고 첫 번째 매개변수는 동일한 타입을 가지므로 할당은 문제 없이 진행된다.


---

# 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://ahnheejong.gitbook.io/ts-for-jsdev/05-type-compatibility/functions.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.
