> For the complete documentation index, see [llms.txt](https://taewoongs-organization.gitbook.io/jtwjs-dev-wiki/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://taewoongs-organization.gitbook.io/jtwjs-dev-wiki/dev_note/typescript/undefined/undefined-4.md).

# 함수 메서드 타이핑

## 함수 및 메서드 타이핑

> 함수의 매개변수를 타이핑하기 위한 다양한 문법이 존재

### 나머지 매개변수 문법

* 나머지 매개변수 문법을 사용하는 매개변수는 항상 배열이나 튜플타입이어야 한다.
* 매개변수의 마지막 자리에만 위치해야함 `(...a: sring[], b: number)`❌

```typescript
function example(...args: [number, string, boolean]) {}
example(1, '2', false);

// 각 매개변수에 임의의 이름을 지정하고 싶다면 아래처럼
function example2(...args: [a: number, b: string, c:boolean]) {}
```

### 함수 내부에서 this를 사용할 때

```typescript
function example() {
  console.log(this); // this: any
}

function exampl2(this: Window) {
  console.log(this); // this: Window
}

function example3(this: Document, a: string, b: 'this') {}
example3.call(document, 'hello', 'this');
```

* **`this`**&#xC758; 타입은 매개변수의 첫 번째 자리에 표기해야 한다.
* ‼️ <mark style="color:red;">**타입스크립트에서 매개변수 자리에 존재하는 this는 실제 매개변수가 아니다.**</mark>
* this에 타입을 표기했다고 해서 this를 쓸 수 있는게 아닌 this 바인딩 기법을 통해 (call, bind 등)으로 this의 값을 명시적으로 지정해주어야 한다.
* (클래스, 객체) 메서드의 경우 일반적으로 this는 메서드를 갖고 있는 객체 자신으로 추론되기 때문에 명시적으로 작성하지 않아도 된다.

### 같은 이름의 함수를 여러번 선언

> TS는 매개변수에 어떤 타입과 값이 들어올지 미리 타입을 선언해야 한다.

#### 오버로딩 (overloading)

* 호출할 수 있는 함수의 타입을 미리 여러개 타이핑해두는 기법
* 너무 지나치게 오버로딩을 활용하면 안됨 (애초에 오버로딩 할 필요가 없는 경우는 사용 ❌)
* <mark style="color:red;">**유니온이나 옵셔널 매개변수를 활용할 수 있는 경우는 오버로딩을 사용하지 말자.**</mark>

```typescript
// 타입만 있고 함수의 구현부는 없음
function add(x: number, y: number): number
function add(x: string, y: string): string
// any를 명시적으로 사용한 처음이자 마지막인 사례
// any를 제거하면 implictAny 에러가 발생하여 쩔수없이 넣을수밖에
// any로 지정한다고 해서 x,y가 any가 되는것은 아님, 오버로딩한 타입의 조합만 가능
function add(x: any, y: any) {
  return x + y;
}

add(1, 2); // 3
add('1', '2'); // 12
add(1, '2'); // error
add('1', 2); // error
```

* 오버로딩을 선언하는 순서도 타입 추론에 영향을 미침
* <mark style="color:purple;">**여러 오버로딩에 동시에 해당될 수 있는 경우는 제일 먼저 선언된 오버로딩에 해당됨**</mark>
* <mark style="color:red;">**오버로딩의 순서는 좁은 타입으로부터 넓은 타입순으로 오게 해야 문제가 없다.**</mark>
* 타입스크립트는 함수에 오버로딩이 있을 때 위에서부터 순서대로 검사한다.

```typescript
function example(param: string): string;
function example(param: string | null): number
function example(param: string | null): string | number {
  if (param) {
    return 'string';
  } else {
    return 123;
  }
}

const result = example('what'); // result: string
```

* 타입 별칭으로도 오버로딩 표현 가능

```typescript
// interface
interface Add {
  (x: number, y: number): number;
  (x: string, y: string): string;
}
const add: Add = (x: any, y: any) => x + y;

type Add1 = (x: number, y: number) => number;
type Add2 = (x: string, y: string) => string;
type Add = Add1 & Add2;
const add: Add = (x: any, y: any) => x + y;

add(1, 2); //3
add('1', '2'); //12
add(1, '2'); //error
add('1', 2); //error
```

### 콜백 함수의 매개변수는 생략 가능

* 인수로 제공하는 콜백 함수의 매개변수에는 타입을 표기하지 않아도 된다.
  * 함수를 선언할 때 매개변수로로 넘길 콜백함수의 타입을 표기했기 때문에 추론이 된다.
  * 이를 문맥적 추론(Contextual Typing) 이라 한다.
* 콜백함수의 매개변수는 함수를 호출할 때 사용하지 않아도 된다.
  * 사용하지 않는다고 해서 옵셔널로 만들면 값이 `| undefined`로 추론되기에 의도와 달라진다.
  * `forEach`메서드가 딱 이 형태
* 콜백 함수의 반환값이 **`void`** 인 경우 어떠한 반환값이 와도 상관없다. (즉, 타입에러가 나지 않음)
  * 다만 해당 반환값은 다른 곳에 사용되지 않음

```typescript
function example(callback: (err: Error, result: string) => void) {}
example((e, r) => {});
example(() => {});
example(() => true);
```

### 공변성과 반공변성

> 공변성과 반공변성을 알아야 함수끼리 대입할 수 있다.

* 어떤 함수는 다른 함수에 대입할 수 있고, 어떤 함수는 대입할 수 없다.&#x20;
  * 이를 이해하려면 공변성과 반공변성 개념을 먼저 알아야함
* A -> B 즉, A는 B에 대입할 수 있다.
* **공변성**: **A -> B** 일 때 **`T<A> -> T<B>`** 인 경우
* **반공변성**: **A -> B** 일 때 **`T<B> -> T<A>`** 인 경우
* **이변성**: **A -> B** 일 때 **`T<A> -> T<B>`** 도 되고 **`T<B> -> T<A>`** 도 되는 경우
* **무공변성**: **A -> B** 일 때 **`T<A> -> T<B>`** 도 안 되고 **`T<B> -> T<A>`**&#xB3C4; 안 되는 경우\\
* <mark style="color:purple;">**기본적으로 타입스크립트는 공변성을 가지고 있다.**</mark>
* 단, <mark style="color:red;">**함수의 매개변수는 반공변성**</mark> <mark style="color:green;">**(넓 -> 좁)**</mark>특징을 갖는다.
  * TS Config 메뉴에서 strictFunctionTypes 옵션이 체크되있어야함&#x20;
  * **strict** 옵션이 체크되어있으면 자동 활성화
  * strictFunctionTypes 모두 체크되어있지 않다면 타입스크립트는 매개변수에 이변성을 갖는다.
* <mark style="color:red;">**반환값은 무조건 항상 공변성**</mark>**&#x20;**<mark style="color:green;">**(좁 -> 넓)**</mark>을 갖는다.
* 단, `함수(매개변수): 반환값` 으로 선언한 것은 매개변수가 이변성을 가짐
  * `함수: (매개변수) ⇒ 반환값`으로 선언한 것은 반공변성을 가진다.

```typescript
// a -> b, 좁은 타입에서 넓은 타입으로 대입할 수 있는 
function a(x: string): number { return 0 } // 더 좁은 타입

type B = (x: string) => string | number; // 더 넓은 타입
let b: B = a; 
```

```typescript
function a(x: string | number): number { return 0 }
type B = (x: string) => number
let b: B = a; // 매개변수는 반공변성이므로 넓은 타입에서 -> 좁은 타입으로 대입 가능
```
