2024년 4월 16일
우리는 보통 컴포넌트 안에 내용물 자체를 넣어줄때, children으로 넣어준다.
대표적으로 모달의 Backdrop이 있다.
import { ReactNode } from 'react';
interface BackdropProps {
  children: ReactNode;
}
export default function BackDrop({ children }: BackdropProps) {
  return <div>{children}</div>;
}
기본적으로 children에 대한 타입을 지정해줄때 ReactNode로 지정해준다.
JSX.Element나 ReactChild같은 속성도 존재하지만, 이는 문자열이나 배열은 받지 못하므로 ReactNode를 많이 사용한다.
하지만 이마저도, 새로운 레포를 만들때마다 children에 대한 타입을 만들어주어야하므로 번거로움을 느낄 수 있다.
그러므로 리액트에서 공식적으로 children에 대한 타입을 지정하기 위해서 PropsWithChildren이라는 타입을 만들었다.
type PropsWithChildren<P = unknown> = P & {
  children?: ReactNode | undefined;
};
보면 제네릭을 통해 기존 props에 대한 인자들을 받고, children은 옵셔널로 ReactNode 타입으로 지정해준 것을 볼수 있다.
import { PropsWithChildren } from "react";
interface LabelProps {
  htmlFor: string;
}
export default function Label({
  htmlFor,
  children,
}: PropsWithChildren<LabelProps>) {
  return <label htmlFor={htmlFor}>{children}</label>;
}
export default function BackDrop({ children }: PropsWithChildren) {
  return <div>{children}</div>;
}
위처럼, 내장된 타입을 이용한다면 간단하게 children에 대한 타입을 정의해줄수 있다.
하지만 PropsWithChildren은 옵셔널이기때문에, children이 undefined이면 안될 경우에는 완벽히 대응해주지 못한다.
export type StrictPropsWithChildren<P = unknown> = P & {
  children: ReactNode;
};
이런식으로 옵셔널이 아닌 ReactNode만을 인자로 받는 타입을 새롭게 만들어준다면, 더더욱 안정적으로 children을 props로 받아줄수 있다.