Item 12 함수 표현식에 타입 적용하기

Use Function Expressions

함수를 정의하는 방법은 대표적으로 문장(statement) 또는 표현식(expression)이 있다.

function rollDice1(sides: number): number { /* ... */ }          // 문장
const rollDice2 = function(sides: number): number { /* ... */ }  // 표현식
const rollDice3 = (sides: number): number => { /* ... */ }       // 표현식

타입스크립트에서는 함수 표현식을 사용하는 것이 좋다(고 한다). 함수의 매개변수부터 반환값까지 전체를 함수 타입으로 선언하여 함수 표현식에 재사용할 수 있기 때문이다. 따라서 불필요한 코드의 반복을 줄인다.

type DiceRollFn = (sides: number) => number
const rollDice: DiceRollFn = sides => { /* ... */ }
function add(a: number, b: number) { return a + b }
function sub(a: number, b: number) { return a - b }
function mul(a: number, b: number) { return a * b }
function div(a: number, b: number) { return a / b }

v.s.

type BinaryFn = (a: number, b: number) => number
const add = (a, b) => a + b
const sub = (a, b) => a - b
const mul = (a, b) => a * b
const div = (a, b) => a / b

아래가 더 깔끔해보인다.

fetch 함수를 예로 들어보자.

lib.dom.d.ts
declare function fetch(
  input: RequestInfo, ini?: RequestInit
): Promise<Response>

아래의 함수를 작성할 수 있다.

async function checkedFetch(input: RequestInfo, init?: RequestInit) {
  const response = await fetch(input, init)
  if (!response.ok) {
    throw new Error('Request failed: ' + response.status)
  }
  return response
}

이 코드도 잘 동작하지만, 아래처럼 더 간결하게 작성할 수 있다.

const checkedFetch: typeof fetch = (input, init) => {
  const response = await fetch(input, init)
  if (!response.ok) {
    throw new Error('Request failed: ' + response.status)
  }
  return response
}
  • 이렇게 하면 input, init의 타입을 추론해서 생략할 수 있다.

  • 또한, throw 대신 return을 실수로 적었다면, 그 실수도 잡을 수 있다.

Summary

  • 매개변수나 반환 값에 타입을 명시하기보다는, 함수 표현식 전체에 타입 구문을 적용하는 것이 좋다.

  • 만약 같은 타입 시그니처를 반복적으로 작성한 코드가 있다면 함수 타입을 분리해 내거나 이미 존재하는 타입을 찾아보도록 한다. 라이브러리를 직접 만든다면 공통 콜백에 타입을 제공해야 한다.

  • 다른 함수의 시그니처를 참조하려면 typeof fn을 사용하자.

Last updated