리액트에서 children 타입 정의하기

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.ElementReactChild같은 속성도 존재하지만, 이는 문자열이나 배열은 받지 못하므로 ReactNode를 많이 사용한다.

하지만 이마저도, 새로운 레포를 만들때마다 children에 대한 타입을 만들어주어야하므로 번거로움을 느낄 수 있다.


- PropsWithChildren

그러므로 리액트에서 공식적으로 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로 받아줄수 있다.

StrictPropsWithChildren에 대한 글