📍 문제가 발생한 상황
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
'배워서 남 주자' 카테고리의 다른 글
디자인 패턴 - 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 |