React - prop-types ( vs TypeScript )

김정인·2023년 1월 25일
0

React

목록 보기
4/4

📌 props-types란?


PropTypes는 React의 props에 대한 런타임 유형 검사 도구입니다.
React 15.5부터 사용할 수 있으며, props-types를 사용하면 props가 필수인지 선택 사항인지 명시하는 것과 같이 컴포넌트에서 예상되는 props유형을 정의할 수 있습니다. 컴포넌트에 다른 유형을 전달하거나 필수 props를 전달하지 않으면 JavaScript 콘솔창에 경고문이 표시됩니다.


🔎 propTypes (+isRequired)

props의 타입을 지정하여 다른 타입의 값이 들어왔을 때 콘솔창에서 경고문을 확인할 수 있습니다.
또한 타입 뒤에 .isRequired를 붙여주면 필수 props로 인식하여, 값이 없는 경우 콘솔창에 에러가 발생합니다.

  • propTypes는 성능상의 이슈로 개발 모드에서만 유효하고, 실제 프로덕션에서는 아무런 영향을 주지 않습니다.

    콘솔창에서 에러 로그를 확인 할 수 있긴하지만, vscode(IDE)에서는 오류나 경고를 표시하지 않습니다. PropsTypes는 프로덕션 응용 프로그램(vscode)에서 경고를 따로 제공하지 않으며 경고는 개발 중에만 표시되어집니다.
  • propsTypes의 타입의 종류는 아래와 같습니다.

    import PropTypes from 'prop-types';
    
    MyComponent.propTypes = {
      optionalArray: PropTypes.array,
      optionalBool: PropTypes.bool,
      optionalFunc: PropTypes.func,
      optionalNumber: PropTypes.number,
      optionalObject: PropTypes.object,
      optionalString: PropTypes.string,
    
      // ES6 Symbol
      optionalSymbol: PropTypes.symbol,
    
      // 렌더링할 수 있는 모든 것(number, string, JSX code, ...)
      optionalNode: PropTypes.node,
    
      // React 엘리먼트
      optionalElement: PropTypes.element,
    
      // React 엘리먼트 타입 (ie. MyComponent)
      optionalElementType: PropTypes.elementType,
    
      // prop가 클래스의 인스턴스임을 선언할 수 있습니다.
      // JavaScript의 instanceof 연산자를 사용합니다.
      optionalMessage: PropTypes.instanceOf(Message),
    
      // 열거형(enum)으로 처리하여 prop가 특정 값들로 제한되도록 할 수 있습니다.
      optionalEnum: PropTypes.oneOf(['News', 'Photos']),
    
      // 여러 종류중 하나의 종류가 될 수 있는 객체
      optionalUnion: PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.number,
        PropTypes.instanceOf(Message)
      ]),
    
      // 특정 타입의 행렬
      optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
    
      // 객체의 모든 키 값이 주어진 PropType인 객체
      optionalObjectOf: PropTypes.objectOf(PropTypes.number),
    
      // 특정 형태를 갖는 객체
      optionalObjectWithShape: PropTypes.shape({
        color: PropTypes.string,
        fontSize: PropTypes.number
      }),
    
      // An object with warnings on extra properties
      optionalObjectWithStrictShape: PropTypes.exact({
        name: PropTypes.string,
        quantity: PropTypes.number
      }),
    
      // 모든 데이터 타입이 가능
      requiredAny: PropTypes.any,
    };

ex) 사용 예시

import React from "react";
import PropsTypeTest from "./PropsTypeTest";

function App(){
  return (<PropsTypeTest value={100}/>)
}

export default App;
import React from "react";
import PropTypes from "prop-types";

function PropsTypeTest({name,value}){
    return ( 
        <div>
            <p>{name}</p>
            <p>{value}</p>
        </div>
    );
}
   
PropsTypeTest.propTypes = {
    name: PropTypes.string.isRequired,
    value: PropTypes.string,
};
 
  
export default PropsTypeTest;

위와 같이 name, value 값을 string형, name은 isRequired를 붙여 필수 값으로 지정했을 때 name 값을 넘기지 않거나 value 값에 number 타입 값을 전달하면 콘솔창에 에러 로그가 찍히는 것을 확인할 수 있습니다.



🔎 defaultProps

defaultProps를 사용하면 부모 컴포넌트에서 자식 컴포넌트로 해당 속성을 지정하지 않았을 경우, 지정할 기본값을 설정할 수 있습니다.

propTypes의 타입 확인은 defaultProps에도 적용되게 하기 위하여 defaultProps가 처리된 뒤에 일어납니다.


ex) 사용 예시

  • 위 App 컴포넌트에서 PropsTypeTest에 내려주던 value 값을 지우고
  • PropsTypeTest 컴포넌트에 아래 코드만 추가시켜주면 됩니다.
PropsTypeTest.defaultProps = {
    name: "myName",
    value: "myValue",
};

위와 같이 defaultProps를 사용하여 name, value에 기본값을 설정하면 부모 컴포넌트에서 해당 속성을 주지 않았을 때 기본값으로 설정되는 것을 확인할 수 있습니다.



📌 PropTypes와 TypeScript


PropTypes를 보다보니 그냥 TypeScript 쓰는거랑 뭐가 다른거지..? 라는 생각이 들어 찾아봤습니다.

TypeScript에 대한 간략한 설명

  • TypeScript란 JavaScript에 타입을 부여한 언어입니다.
    • 동적인 JavaScript를 정적 언어로 사용하기 위해
    • 정적 언어는 컴파일시 타입이 결정되고, 동적 언어는 런타임에 타입이 결정

  • TypeScript는 JavaScript와 다르게 브라우저에서 실행하기 위해 파일을 컴파일하는 과정이 필요합니다.

  • TypeScript는 예기치 않은 props를 전달할 때 vscode(IDE)에 즉각적인 경고를 표시합니다.
    • 코드를 작성하는 순간 바로 오류 캐치 가능

🔎 PropTypes vs TypeScript 비교

두 도구는 모두 props의 타입 체크에 사용됩니다. 그렇다면 어떤 프로젝트에 어떤 도구를 사용하면 좋을지에 대해 고려해야할 몇 가지 주요 차이점에 대해 정리해보겠습니다.

1. 컴파일타임 및 런타임 유형 확인

컴파일타임과 런타임 간단 정리

  • 컴파일타임(Compile Time)
    개발자에 의해 C, JAVA 등과 같은 소스코드가 작성되며, 컴파일 과정을 통해 컴퓨터가 인식할 수 있는 기계어 코드로 변환되어 실행 가능한 프로그램이 되는 과정입니다.

    • 컴파일에러
      소스코드가 컴파일 되는 과정 중 발생하는 Syntax Error, 파일 참조 에러 등과 같은 문제들로 인해 컴파일이 방해되어 발생하는 오류를 의미하며, 현재 문제가 되는 소스코드를 IDE에서 알려줍니다.


  • 런타임(Run Time)
    컴파일 과정을 마친 응용 프로그램이 사용자에 의해서 실행되어 지는 때를 의미합니다.

    • 런타임에러
      이미 컴파일이 완료되어 프로그램이 실행중임에도 불구하고, 의도치 않은 예외상황으로 인하여 프로그램 실행 중에 발생하는 오류 형태를 의미합니다.
  • PropsTypes는 애플리케이션이 브라우저에서 실행되는 동안 런타임 중 유형 검사를 수행합니다.
  • TypeScript는 TypeScript 코드가 JavaSciprt로 컴파일될 때 컴파일 시간 동안 유형 검사를 수행합니다.

🧐 어떤 경우에 런타임 단계에서 TypeScript에서 체크하지 못하는 타입 불일치가 발생할까?

컴파일 단계를 건너뛰고 런타임에서 처음 등장하는 데이터는 외부 데이터(API 응답 데이터, 로컬 스토리지 등) 뿐입니다.

  • 즉, TypeScript사용 시 외부 데이터는 런타임 단계에서 타입 불일치가 발생할 가능성이 있습니다.
  • PropTypes는 런타임 중 타입 체크를 하기 때문에 오류를 발견할 수 있습니다.

2. 구문 및 의미 강조

두 도구 모두 컴포넌트의 props에 대한 정보와 함께 자동 완성 기능을 제공하는 플러그인이 있고, TypeScript의 표시 도구가 PropTypes를 능가한다고 합니다.


3. TypeScript의 고급 기능

PropTypes가 제공할 수 없는 TypeScript의 props 유형을 지정할 수 있는 방법은 여러 가지가 있습니다. 예를 들면 인터페이스끼리 합치거나, 조건부 타입 체킹이 가능합니다.


🔎 PropTypes와 TypeScript 양쪽의 장점을 모두 가지려면?

1. InferProps

InferPropTypes @types/prop-types의 유형을 사용하여 PropTypes 정의에서 유형 정의를 만들 수 있습니다.

import React from "react";
import PropTypes, { InferProps } from "prop-types";

const BlogCardPropTypes = {
    title: PropTypes.string.isRequired,
    createdAt: PropTypes.instanceOf(Date),
    authorName: PropTypes.string.isRequired,
};

type BlogCardTypes = InferProps<typeof BlogCardPropTypes>;
const BlogCard = ({ authorName, createdAt, title }: BlogCardTypes) => {
    return <span>Blog Card</span>;
};

BlogCard.propTypes = BlogCardPropTypes;

export default BlogCard;

구성 요소에 PropTypes 정의가 있으며 TypeScript 유형을 위반할 경우 오류가 발생합니다. 위처럼 'authorName'은 누락되었다고 표시되지만 BlogCardPropTypes 속성에 isRequired를 추가하지 않았기 때문에 createdAt은 누락되었다고 표시되지 않습니다.


2. babel-plugin-typescript-to-proptypes

babel-plugin-typescript-to-proptypes를 사용하여 TypeSciprt 유형 정의에서 PropTypes를 생성할 수 있습니다. props 유형을 지정하면 플러그인이 해당 유형 정의를 PropTypes 정의로 변환합니다.

import React from "react";
type Props = {
    title: string;
    createdAt: Date;
    authorName: string;
};
const BlogCard = ({ title, createdAt, authorName }: Props) => {
    return <span>Blog card</span>;
};
export default BlogCard;

위 코드는 아래와 같이 작성된 것처럼 작동합니다.

import React from 'react'
import PropTypes from 'prop-types'

const BlogCard = ({ title, createdAt, authorName }) => {
    return <span>Blog card</span>;
};

BlogCard.propTypes = {
  title: PropTypes.string.isRequired,
  createdAt: PropTypes.instanceOf(Date),
  authorName: PropTypes.string.isRequired,
}

export default BlogCard

3. brieb/props-type.ts

타입스크립트 유틸리티 타입을 통해 런타임 타입 체크를 하는 구현 방법입니다.
Adopting Typescript at Scale 강의를 참고하면 좋습니다.


4. prop-types-ts

타입스크립트 런타임 타입 시스템인 io-ts를 기반으로 제작된 라이브러리입니다.


5. ts-react-loader

props 인터페이스를 기반으로 런타임 타입 체크 코드를 자동으로 생성해주는 웹팩 로더입니다.


📌 PropTypes vs TypeScript 결론


검색해본 결과 범용적으로 TypeScript를 더 많이 사용하고 있는 것 같습니다. 하지만 외부 데이터(API 응답 데이터, 로컬 스토리지 등)를 자주 가져오는 상황이라면 타입 불일치로 인한 런타임 에러의 가능성(런타임 에러가 최악인 이유 보러가기)을 염두해두어여하고 완벽한 휴먼 에러의 사전 방지를 원한다면 PropTypes의 사용이 더 좋을 것 같다는 생각이 듭니다.
각 프로젝트 별로 적합한 도구를 선택하여 사용하거나 양쪽 모두의 장점을 살릴 수 있는 방법을 채택하는 것도 좋을 것 같습니다.



🙇🏻‍♂️ 참고한 글

Comparing TypeScript and PropTypes in React applications
타입스크립트에서 prop-types를 사용할까?
React Component Props Typing with propTypes and defaultProps in TypeScript

profile
FE 개발자

0개의 댓글