배워서 남 주자

[TypeScript] React에서 rest props의 타입 지정은 어떻게 할 수 있을까?

미래에서 온 개발자 2023. 11. 1. 22:04

 📍 문제가 발생한 상황

ant design 라이브러리를 사용한 프로젝트에서 Modal 컴포넌트의 modal open 관련 로직을 별도의 ui 컴포넌트로 작성해 사용하는 쪽에서는 관련 로직에 대한 상태 없이도 사용할 수 있게 설계하고자 했다. 처음에 생각한 코드는 다음과 같다. 

 

import { Modal as AntdModal } from 'antd';

function Modal({ title, children, ...rest }) {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <AntdModal title={title} open={isOpen} onCancel={() => setIsOpen(false)} {...rest}>
      {children}
    </AntdModal>
  );
}

 

이렇게 선언한 컴포넌트를 사용부에서는 다음과 같이 호출한다. centered나 width 같은 스타일 관련 속성은 사용부에 따라 달라질 수 있는 속성이기 때문에 Modal 컴포넌트에서는 모달의 로직과 관련한 부분만 두고, 스타일 등은 사용부에서 결정한다. 

import { Modal } from '@/components/ui/Modal';

export default function DueDateModal() {
  return (
    <Modal title="마감일 선택" centered width={360}>
      <Inner />
    </Modal>
  );
}

 

타입스크립트 프로젝트이기 때문에 Modal 컴포넌트의 props에 대한 타입을 지정해 줘야 했다. 보통 props에 대한 타입은 아래와 같이 작성한다. 

type Props = {
  title: string;
  children: React.ReactNode;
};

function Modal({ title, children, ...rest }: Props) {
  // 생략

  return (
    <AntdModal title={title} open={isOpen} onCancel={() => setIsOpen(false)} {...rest}>
      {children}
    </AntdModal>
  );
}

 

하지만 이렇게만 작성하면 Modal 컴포넌트를 호출하는 파일에서 centered와 width 속성이 정의되지 않았기 때문에 다음과 같은 ts 에러가 발생한다.

'{ children: Element; title: string; centered: boolean; width: number; }' 형식은 'IntrinsicAttributes & Props' 형식에 할당할 수 없습니다. 'IntrinsicAttributes & Props' 형식에 'width' 속성이 없습니다.ts(2322)

 

 

...rest에 대한 타입 정의를 어떻게 해줘야 할까? 

 

💡 해결책

console을 찍어보면 rest는 결국 다음과 같이 key-value 쌍을 가진 객체이다. 

type Props = {
  title: string;
  children: React.ReactNode;
};

function Modal({ title, children, ...rest }: Props) {
  // 생략
  console.log(rest); // {centered: true, width: 360}

  return (
    <AntdModal title={title} open={isOpen} onCancel={() => setIsOpen(false)} {...rest}>
      {children}
    </AntdModal>
  );
}

 

즉, 컴포넌트의 선언 시점에는 어떤 property가 들어올지 모른다. 이럴 때 사용할 수 있는 것이 바로 index signature 문법이다. javascript에서 객체의 key는 전부 string이기 때문에 다음과 같이 Props를 정의해 ts 에러를 해결할 수 있다. 

 

type Props = {
  title: string;
  children: React.ReactNode;
  [property: string]: any; // for rest props
};

 

 

📚 참고 자료

https://stackoverflow.com/questions/40032592/typescript-workaround-for-rest-props-in-react

 

TypeScript workaround for rest props in React

Updated for TypeScript 2.1 TypeScript 2.1 now supports object spread/rest, so no workarounds are needed anymore! Original Question TypeScript supports JSX spread attributes which is commonly use...

stackoverflow.com

 

'배워서 남 주자' 카테고리의 다른 글

디자인 패턴 - Presentational/Container 패턴  (0) 2023.11.22
디자인 패턴 - Compound 패턴  (0) 2023.11.05
디자인 패턴 - Flyweight 패턴  (2) 2023.10.29
디자인 패턴 - Mixin 패턴  (1) 2023.10.26
super 키워드  (1) 2023.10.22