React 56장 - 이벤트의 타입
포스트
취소

React 56장 - 이벤트의 타입

React

TypeScript

  • 리액트와 타입스크립트를 함께 사용하다보면 이벤트 타입을 정의해줘야 하는 순간이 온다.
  • 사실 타입스크립트를 사용하다 보면 생각보다 타입 지정을 요구하는 경우가 드물다는 것을 느낀다.
  • 하지만 요소에서 발생하는 이벤트를 다루려면 높은 확률로 타입을 지정해줘야 한다.
  • 기존에는 필요할 때마다 input, button... 등의 요소에서 발생하는 타입을 찾아서 작성하였다.
  • 이번에 이벤트 타입에 대해서 더 찾아보며 알게된 것들을 정리하고자 한다.

EventHandler, Event

  • 계속 헷갈렸던 개념인데, 쉽게 생각해 EventHandler는 함수를 정의할 때, Event는 실제 이벤트가 발생한 객체를 정의할 때 사용된다.
1
2
3
4
5
6
7
const clickHandler:MouseEventHandler<HTMLButtonElement> = () => {
    ...
}

const clickHandler = (e:MouseEvent<HTMLButtonElement>) => {
    ...
}

이벤트 타입 확인하기

  • MouseEvent, ChangeEvent... 등 이벤트를 확인할 때 Ctrl + 클릭을 사용하거나, node_modules/@types/react/ts에 들어가보면 여러가지 이벤트를 확인할 수 있다.
  • 여기서 다양한 타입을 확인할 수 있는데 좋은 자료가 있어서 가져왔다.
  • 버튼 컴포넌트를 만든다고 했을 때, onClick이라는 함수를 props로 받는다고 가정하자.
1
2
3
4
5
6
7
8
9
10
11
12
13
interface Props {
  onClick(): void;
}

function Button({ onClick }: Props) {
  return <button onClick={onClick}>클릭 이벤트</button>;
}

function App() {
  function onClick(e: React.MouseEvent) {}

  return <Button onClick={onClick} />;
}
  • 이렇게 작성된 코드의 onClick 함수의 타입은 매개변수에 대한 타입을 별도로 지정하지 않았기 떄문에 타입 에러가 발생한다.
1
Type '(e: MouseEvent<Element, MouseEvent>) => void' is not assignable to type '() => void'.

타입 추론하기

  • 타입 에러에 대한 구문만 보고도 유추하여 작성할 수 있지만, 위의 @types파일을 좀 더 파헤쳐보기로 한다.
  • 우선 마우스 이벤트 핸들러가 지정된 타입을 찾는다.
  • 여기서 사용되는 Element는 우리가 사용할 요소가 되며, HTMLButtonElement를 뜻한다.
  • 이것을 풀어서 설명해보자면 EventHandlerMouseEvent 구문과 같게 작성할 수 있다.
1
2
3
4
5
type MouseEventHandler<T = Element> = EventHandler<MouseEvent<T>>;

=== // 이 두 가지 코드는 동일하다.

type MouseEventHandler<HTMLButtomElement> = EventHandler<MouseEvnet<HTMLButtomElement>>;
  • 마우스 이벤트 핸들러와 관련된 코드는 아래와 같다.
1
2
3
4
5
6
7
type MouseEventHandler<T = Element> = EventHandler<MouseEvent<T>>;

interface MouseEvent<T = Element, E = NativeMouseEvent> extends UIEvent<T, E> {}

type EventHandler<E extends SyntheticEvent<any>> = {
  bivarianceHack(event: E): void;
}["bivarianceHack"];
  1. MouseEventHandler는 기본적으로 Element를 매개변수로 받을 수 있으며, EventHandlerElement를 매개변수로 받는 MouseEvent를 매개변수로 받을 수 있다.
  2. MouseEventElementNativeMouseEvent 를 매개변수로 받으며, UIEvent와 마우스 이벤트 간에 공통 속성을 상속받는다.
  3. SyntheticEvent는 합성 이벤트로, 리액트에서 이벤트 시스템과 호환되도록 만들어지는 객체이다.
  4. bivarianceHack이라는 속성을 가진 객체는 아래의 정보로 bivarianceHack 이란

좀 더 간편하게 이벤트 사용하기

  • 나는 매번 MouseEvent인지 다른 이벤트인지 헷갈린다.
  • 이벤트 핸들러 타입과 HTMLElement를 매번 떠올려야 하는 번거로움이 있는데 props로 이를 해결하는 방법이 있다.
1
2
3
4
5
6
7
8
9
import {ComponentProps} from "react";

function Component(){
    const handleChange : ComponentProps<'input'>['onChange'] = (e) => {
        ...
    }

    return <input onChange={handlerChange}/>;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { ComponentProps, DOMAttributes } from 'react';

type EventHandlers<T> = Omit<
  DOMAttributes<T>,
  'children' | 'dangerouslySetInnerHTML'
>;

export type Event<
  TElement extends keyof JSX.IntrinsicElements,
  TEventHandler extends keyof EventHandlers<TElement>
> = ComponentProps<TElement>[TEventHandler];


function Component() {
  const handleChange: Event<'input', 'onChange'> = (e) => {
    console.log(e.target.value);
  };

  return <input onChange={handleChange} />;
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.