TypeScript + React: Typing custom hooks with tuple types

간단한 toggle hook의 예제 입니다.

export const useToggle = (initialValue: boolean) => {
  const [value, setValue] = useState(initialValue)
  const toggleValue = () => setValue(!value)
  return [value, toggleValue]
}
export const Body = () => {
  const [isVisible, toggleVisible] = useToggle(false)
  return (
    <>
      {/* It very much booms here! 💥 */ }
      <button onClick={toggleVisible}>Hello</button>
      {isVisible && <div>World</div>}
    </>
  )
}

이 예제는 에러가 발생합니다. onClick 시에 event : MouseEvent <HTMLButtonElement, MouseEvent> 파라미터를 전달하기 때문입니다.

이는 타입이 잘못되었기 때문입니다. any[] ? 우리는 배열을 다루지 않습니다. 명시적인 튜플 타입을 만들어 주면 사용하지 않는 파라미터에 대한 에러를 없앨 수 있습니다.

Tuple 타입으로 변경합시다! Javascript에서는 배열과 Tuple을 구분할 수 없지만 Typescript는 가능합니다.

옵션 1 : Return 타입에 튜플 타입 추가

Return 타입을 명시적으로 지정합니다.

// add a return type here
export const useToggle = (initialValue: boolean): [boolean, () => void] => {
  const [value, setValue] = useState(initialValue)
  const toggleValue = () => setValue(!value)
  return [value, toggleValue]
}

옵션 2 : as const

튜플을 사용하면 예상되는 요소의 갯수와 타입을 알고 있습니다. 이것은 const assertion 처럼 들리지 않습니까?

export const useToggle = (initialValue: boolean) => {
  const [value, setValue] = useState(initialValue)
  const toggleValue = () => setValue(!value)
  // here, we freeze the array to a tuple
  return [value, toggleValue] as const
}