티스토리 뷰

React

[React] PropTypes로 Prop타입 체크

_Woogie 2022. 12. 15. 19:47

개발하면서 앱이 커질수록 타입체크는 더욱 잘해야하고 타입 검사를 잘 활용하면 많은 버그를 잡을 수 있다.

React에는 내장된 타입 검사 기능들을 갖고 있다. 컴포넌트간 데이터를 전달하는 prop에 타입체크를 하는 것은 필수적으로 해줘야 미래의 내가 덜 고생하는 길이 될 수 있다.

 

PropTypes

컴포넌트의 prop에 타입 검사를 하기 위해 prop를 받는 하위컴포넌트에 PropTypes를 선언해준다.

import PropTypes from "prop-types";

prop에 유효하지 않은 값이 전달되면 콘솔에 경고문이 보일 것이다.

경고: "타입이 배열인데 숫자가 웬말이냐"

 

타입이 다르면 실행을 아예 안시키는 타입스크립트와 달리 자바스크립트에선 실행은 시켜주는 대신 콘솔에 저런 경고문을 띄워준다. 그리고 저 경고문은 propTypes 성능상의 이유로 개발 모드에서만 확인할 수 있다.

 

import React from "react";
import PropTypes from "prop-types";

const Board = ({ articles }) => {
  return (
    <ul>
      {articles.map((article) => (
        <li key={article.id}>
          {article.id} | {article.title}
        </li>
      ))}
    </ul>
  );
};

Board.propTypes = {
  articles: PropTypes.array,
};

export default Board;

자식컴포넌트인 Board에서 prop 타입 체크하는 코드이다.

 

PropTypes를 사용함으로써 또 하나의 장점은 타입 정의만으로 좋은 코드가 될 수 있다는 점이다.

const User = ({ type, age, male, onChangeName, onChangeTitle }) => {
  
  const onClick1 = () => {
    const msg = `type: ${type}, age: ${age ? age : '알 수 없음'}`
    log(msg, { color: type === "gold" ? "red" : "black" })
    // ...
  }
  
  const onClick2 = () => {
  	if (onChangeName) onChangeName(name)
    onChangeTitle(title) 
    male ? goMalePage() : goFemalePage()
    // ...
  }
  // ...
}

위 코드처럼 코드를 자세히 뜯어보지 않는이상 타입을 한번에 알기가 어렵다.

 

User.propTypes = {
  male: PropTypes.bool.isRequired,
  age: PropTypes.number,
  type: PropTypes.oneOf(["gold", "silver", "bronze"]),
  onChangeName: PropTypes.func,
  onChangeTitle: PropTypes.func.isRequired
}

const User = ({ type, age, male, onChangeName, onChangeTitle }) => {
  // ...

이렇게 PropTypes로 타입을 명시해주면 코드를 뜯어보지 않고도 타입을 한번에 알 수 있고 협업할때 일의 능률도 올라갈 것이다.

 

PropTypes를 사용하여 다양한 유효성 검사를 할 수 있다.

 

예제) 하나의 자식만 요구하기

PropTypes.element를 이용하여 컴포넌트의 자식들에 단 하나의 자식만이 전달될 수 있도록 명시할 수 있다.

// 부모 컴포넌트
...
<PropEx>
    <h1>Hello</h1>
    <h2>World</h2>
</PropEx>
...


// 자식 컴포넌트
import React from "react";
import PropTypes from "prop-types";

const PropEx = ({ children }) => {
  return <div>{children}</div>;
};

PropEx.propTypes = {
  children: PropTypes.element.isRequired, // 타입에러
};

export default PropEx;

경고: 자식요소 하나만 받는다더니 두개 이상이다. 두개 이상의 자식은 배열이다.

 

그 외 PropTypes종류

MyComponent.propTypes = {
  // 리액트 요소
  // <div>123</div> , <Component />
  menu: PropTypes.element,
  
  // 컴포넌트 함수가 반환할 수 있는 모든 것(비추)
  // <SomeComponent />, 123
  description: PropTypes.node,
  
  // Message 클래스로 생성된 모든 객체
  // new Messages() -> 참, new Car() -> 거짓
  message: PropTypes.instanceOf(Message),
  
  // 배열에 포함된 값 중에서 하나를 만족
  name: PropTypes.oneOf(["jake", "olivia"]),

  // 배열에 포함된 타입 중에서 하나를 만족
  width: PropTypes.oneOfType([PropTypes.number, PropTypes.string])

  // 특정 타입만 포함하는 배열
  // [1, 5, 7] -> 참, ['a', 'b'] -> 거짓
  ages: PropTypes.arrayOf(PropTypes.number),

  // 객체의 속성값 타입을 정의
  // {color: 'red', weight: 123} -> 참
  info: PropTypes.shape({
    color: PropTypes.string,
    weight: PropTypes.number
  })

  // 객체에서 모든 속성값의 타입이 같은 경우
  // {prop1: 123, prop2: 456}
  infos: PropTypes.objectOf(PropTypes.number)
}

 

나는 여기서 한가지 의문이 들었다.

타입스크립트에선 PropTypes가 필요없나??

 

결론부터 얘기하자면 완벽한 휴먼에러 퇴치를 원한다면 PropTypes 사용을 권장한다

이유는,

자바스크립트는 동적인 언어이고 런타임에 타입이 결정된다. 그리고 타입스크립트는 정적인 언어로 컴파일 시에 타입이 결정된다. 그렇기 때문에 타입스크립트 코드를 짤 때 IDE에서 미리 경고를 날려주는게 특징이다.

 

다만 외부 데이터를 사용할때, 즉 API 호출을 통해 받아온 응답이나 로컬 스토리지 등의 외부 데이터는 컴파일 단계에서 타입 체크를 할 수 없기 때문에 여기에서 타입 불일치가 발생할 가능성이 있다.

 

그래서 런타임에 타입 체크를 해주는 PropTypes 라이브러리를 사용하는게 좀 더 완벽하게 휴먼 에러를 방지하는 것이라고 볼 수 있다.

타입스크립트 PropTypes의 자세한 내용은 참고

 


참고

 

PropTypes와 함께 하는 타입 검사 – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

 

[React] PropTypes 쓰는 이유, 방법

작업하는 프로젝트의 규모가 커질 수록 생각지 못한 곳에서 에러가 발생하는 일이 잦아진다. 이를 방지하기 위한 방법으로, PropTypes를 활용하여 타입(type)을 확인하는 것이 대표적이다.

velog.io