Logo

PropTypes로 React 입력 타입 체크하기

PropTypes는 React에서 타입 체크를 위해서 사용되는 라이브러리입니다. 이 번 포스팅에서는 PropTypes를 이용해서 React 컴포넌트의 prop에 대한 타입 정의와 기본값 설정을 하는 방법에 대해서 알아보겠습니다.

패키지 설치

PropTypes 라이브러리는 prop-types이라는 패키지 이름을 가지고 있는데요. 기본적으로 react 패키지에 내장이 되어 있기 때문에, React만 설치되어 있다면 별도로 설치할 필요가 없습니다.

예제 컴포넌트

PropTypes를 어떻게 사용하는지 보여드리기 위해서 먼저 예제 컴포넌트를 작성하도록 하겠습니다.

아래 코드는 prop으로 pathchidren, blank, size를 받아서, <a/> 엘리먼트를 랜더링해주는 간단한 React 함수 컴포넌트입니다.

import React from "react";

const BASE_URL = "https://www.daleseo.com";

function Anchor({ path, children, blank, size }) {
  return (
    <a
      href={`${BASE_URL}${path}`}
      target={blank ? "_blank" : "_self"}
      style={{ fontSize: size }}
    >
      {children}
    </a>
  );
}

예를 들어, 위 Anchor 컴포넌트는 다음과 같이 사용할 수 있습니다.

<Anchor path="/react-prop-types" blank size={20}>
  PropTypes
</Anchor>

그러면 실제로 브라우저에서는 다음과 같이 랜더링됩니다.

<a
  href="https://www.daleseo.com/react-prop-types"
  target="_blank"
  style="font-size: 20px;"
  >PropTypes</a
>

타입 체크 부재로 인한 문제점

만약에 Anchor 컴포넌트를 사용하는 사람이 아래와 같은 실수를 한다고 가정해보겠습니다.

children prop을 누락시킨다면?

<Anchor path="/react-prop-types" blank size={20} />

size prop에 숫자가 아닌 문자열을 넘긴다면?

<Anchor path="/react-prop-types" blank size="20">
  PropTypes
</Anchor>

이런 경우, Anchor 컴포넌트는 원치않는 방식으로 랜더링되게 됩니다.

이렇게 React에서 흔히 발생하는 버그는 컴포넌트의 prop에 대한 명시적인 타입 체크를 통해 해결을 할 수 있으며, 이를 도와주는 라이브러리가 PropTypes 입니다.

prop 타입 정의

PropTypes를 이용해서 React 컴포넌트에 prop으로 넘어오는 입력값들이 어떤 타입을 가져야하는지 정의할 수 있습니다.

우선, prop-types 패키지에서 PropTypes 객체를 임포트해야 합니다.

import PropTypes from "prop-types";

PropTypes 객체는 타입을 정의할 때 필요한 다양한 타입 검증자(validator)들을 제공합니다. 그리고 React 컴포넌트의 PropTypes을 이용해 정의된 타입 정보를 할당받기 위한 propTypes 속성을 가지고 있습니다.

예를 들어, 위에서 작성한 Anchor 컴포넌트는 타입 정의는 다음과 같이 할 수 있습니다.

Anchor.propTypes = {
  path: PropTypes.string,
  children: PropTypes.string.isRequired,
  blank: PropTypes.bool,
  size: PropTypes.number,
};

pathchildren prop은 문자열, blank prop은 불리언, size porp은 숫자로 타입을 정의하였습니다. 그리고 children prop은 맨 뒤에 isRequired를 붙임으로써 반드시 입력되어야 하는 필수 prop으로 정의하였습니다.

이렇게 타입 명시적으로 컴포넌트에 넘어올 prop에 대한 타입 정의를 해주면, React는 타입 정의 위반 시 경고 메시지를 콘솔에 출력해줍니다. 예를 들어, size prop에 숫자가 아닌 문자열을 넘기면, 다음과 같은 경고 메시지를 확인하실 수 있으실 겁니다.

<Anchor path="/react-prop-types" blank size="20" />
Warning: Failed prop type: Invalid prop `size` of type `string` supplied to `Anchor`, expected `number`.

이러한 경고 메시지는 개발 모드에서만 출력되기 때문에, 실제 사용자에게 아무 영향을 주지 않으면서, 오직 개발자들만 확인할 수 있습니다.

prop 기본값 설정

추가로 타입 정의와 더불어 많이 사용되는 prop의 기본값을 설정하는 방법을 알아보겠습니다. 타입 정의를 할 때와 비슷한 방식으로 React 컴포넌트는 defaultProps 속성을 가지고 있고, 여기에 기본값을 정의하는 객체를 할당해주면 됩니다.

예를 들어, 위에서 작성한 Anchor 컴포넌트는 기본값 설정은 다음과 같이 할 수 있습니다.

Anchor.defaultProps = {
  path: "/#",
  blank: false,
  size: 16,
};

위와 같이 각 prop에 대한 기본값을 설정해주면, 해당 prop에 입력값이 넘어오지 않은 경우, 이 기본값이 사용됩니다. 그리고 children prop의 경우 위에서 타입을 정의할 때 필수 prop으로 정의하였기 때문에 기본값을 설정해줄 필요가 없습니다.

이제, 다음과 같이 Anchor 컴포넌트에 children prop만을 넘기게 되면,

<Anchor>Home</Anchor>

아래와 같이 prop에 기본값이 설정된 상태로 랜더링이 되게 됩니다.

<a href="https://www.daleseo.com/#" target="_self" style="font-size: 16px;"
  >Home</a
>

전체 코드는 아래에 올려두었으니 참고바라겠습니다.

복잡한 타입 정의

위 예제처럼 단순한 타입이 아닌 복잡한 구조를 가진 객체를 prop으로 받는 컴포넌트들은 어떻게 타입 정의를 할 수 있을까요? PropTypes 객체는 복잡한 타입 정의를 위한 shape(), arrayOf(), oneOf(), instanceOf()와 같은 고급 검증자들도 제공하고 있습니다.

예를 들어, 아래의 UserProfie 컴포넌트의 경우, 필수 prop인 user와 선택 prop인 friends를 갖도록 정의되어 있습니다. user prop의 경우, 숫자 타입인 id 속성과 문자열 타입인 name 속성을 반드시 갖는 객체로 타입이 정의되어 있습니다. avatar는 선택적으로 필요한 속성인데, 필수인 theme 속성은 blackwhite 중 하나의 값이 될 수 있는 Enum 타입이며, 선택인 image 속성은 Image 클래스의 인스턴스여야 합니다.

friends prop의 경우 선택 사항이며, user와 유사한 구조를 가진 객체를 원소로 갖는 배열의 형태로 입력되도록 정의되어 있습니다.

UserProfie.propTypes = {
  user: PropTypes.shape({
    id: PropTypes.number.isRequired,
    name: PropTypes.string.isRequired,
    preference: PropTypes.shape({
      theme: PropTypes.oneOf(["black", "white"]).isRequired,
      image: PropTypes.instanceOf(Image),
    }),
  }).isRequired,
  friends: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.number.isRequired,
      name: PropTypes.string.isRequired,
    }).isRequired
  ),
};

마치면서

지금까지 PropTypes 라이브러리를 사용해서 React 컴포넌트의 타입 체크를 하는 아주 기본적인 방법에 대해서 알아보았습니다. 왠만한 프로젝트에서는 이 정도 수준의 타입 체크만 해줘도 많은 버그를 예방할 수 있을 것이라고 생각합니다. PropTypes 라이브러리에 대한 세부적인 사항들은 아래 사이트를 참고바라겠습니다.