본문 바로가기
개발 공부 일지/TypeScript

공통 컴포넌트에 ComponentPropsWithoutRef<T> 사용하기

by yelimu 2025. 3. 18.

부모로부터 어떤 prop을 전달받아 호출하는 지에 따라 여러가지 모양이나 역할을 하는 컴포넌트를 렌더링할 수 있다.

 

그렇기때문에 재사용하는 공통 컴포넌트의 경우, 필요한 prop을 누락하지 않도록 해야한다.

 

그런데 이걸 가능하게 해주는 유틸리티 타입이 있다. !!!

ComponentPropsWithoutRef<T> 

extends를 통해 상속하면 타입변수 T (예시에서는 "button")가 갖고있는 모든 프로퍼티를 prop으로 받을 수 있다.

 

적용 전 

import { ReactNode } from "react";
import { buttonStyle } from "./style.css";

interface ButtonProps {
  children: React.ReactNode;
  variant: "primary" | "secondary" | "outline" | "accent";
  icon?: ReactNode;
  type?: "button" | "submit" | "reset";  // button 요소에서 사용하는 기본 type 속성
  className?: string;  // 추가적인 className을 지원하도록
  onClick?: React.MouseEventHandler<HTMLButtonElement>;  // 클릭 이벤트 핸들러
  disabled?: boolean;  // disabled 상태
  // button 요소에서 다른 필요한 속성들 추가 가능
}

const ButtonComponent = ({ type = "button", ...args }: ButtonProps) => {
  return (
    <button
      type={type}
      className={`${buttonStyle[args.variant]} ${args.className}`}
      {...args}
    >
      {args.icon}
      {args.children}
    </button>
  );
};

export default ButtonComponent;

 

적용 후

import type { ComponentPropsWithoutRef, ReactNode } from "react";
import { buttonStyle } from "./style.css";

interface ButtonProps extends ComponentPropsWithoutRef<"button"> {
  children: React.ReactNode;
  variant: "primary" | "secondary" | "outline" | "accent";
  icon?: ReactNode;
}

const ButtonComponent = ({ type = "button", ...args }: ButtonProps) => {
  return (
    <button
      type={type}
      className={`${buttonStyle[args.variant]} ${args.className}`}
      {...args}
    >
      {args.icon}
      {args.children}
    </button>
  );
};

export default ButtonComponent;

 

비슷한 역할을 하는 HTMLAttributes<HTMLXXXElement> 도 있다

다만 HTML 요소에서 정의하는 기본 속성만을 받기때문에 icon과 같은 커스텀 prop은 포함되지 않는다

이 경우에는 명시적으로 추가해줘야 한다.