HTMLAttributes


checkbox 타입의 <input> 엘리먼트를 사용하는 Toggle 컴포넌트를 만든다고 가정해보자. <input> 엘리먼트는 autoFocus required readOnly 등의 기본 어트리뷰트 가진다.

만약 <input> 엘리먼트가 기본적으로 받을 수 있는 어트리뷰트를 Toggle 컴포넌트의 props로 넘기고 싶다면? 모든 어트리뷰트에 대한 인터페이스를 정의해야 할까?

이땐 InputHTMLAttributes 타입을 사용하면 된다. 그럼 각 어트리뷰트의 prop 타입을 일일이 정의하지 않아도 된다. 제네릭 TonChange 이벤트 핸들러의 엘리먼트 타입이 들어가므로 HTMLInputElement 같은 타입을 넘기면 된다.

interface InputHTMLAttributes<T> extends HTMLAttributes<T> {
	accept?: string | undefined;
	alt?: string | undefined;
	autoComplete?: string | undefined;
	// ...
	onChange?: ChangeEventHandler<T> | undefined;
}

type ChangeEventHandler<T = Element> = EventHandler<ChangeEvent<T>>;

<aside> 💡 InputHTMLAttributes, InputAttributes 등은 @types/react 패키지에서 제공하는 타입이다

</aside>

참고로 id className draggable 같은 HTML 요소의 공통적인 어트리뷰트는 HTMLAttributes 타입에서 상속 받아 사용하고 있다. DOMAttributes의 제네릭 T는 위와 마찬가지로 엘리먼트 타입을 받는다.

interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {
	// React-specific Attributes
	defaultChecked?: boolean | undefined;
	defaultValue?: string | number | ReadonlyArray<string> | undefined;
	// ...

	// Standard HTML Attributes
	accessKey?: string | undefined;
	className?: string | undefined;
	// ...
}

interface DOMAttributes<T> {
	// ...
	onCopy?: ClipboardEventHandler<T> | undefined;
	// ...
}

활용 예제 ⚡️


<input> 엘리먼트의 기본 어트리뷰트는 InputHTMLAttributes<HTMLInputElement> 타입을 통해 상속받고, label color 같은 컴포넌트 수준에서 필요한 prop만 ToggleProps 인터페이스에 추가해서 사용한다.

한편 size 속성은 **<input>**의 기본 어트리뷰트(number | undefined)지만 프로젝트에서 요구하는 사이즈 타입 TSize에 맞춰야하는 상황이다. 따라서 Omit 유틸리티 타입으로 InputHTMLAttributessize 속성을 제외하고 ToggleProps 인터페이스에 TSize 타입을 추가했다.

import React, { InputHTMLAttributes } from "react";

// TColor : primary | error | background | ...
// TSize : base | lg | md | ...

interface ToggleProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
  className?: string;
  label?: string;
  color?: TColor;
  size?: TSize; // size는 <input>의 기본 어트리뷰트지만 프로젝트에서 요구하는 타입으로 대체
}

export default function Toggle({
  className,
  label,
  color,
  size,
  ...inputProps
}: ToggleProps) {
  // ... 컴포넌트 본문 및 return문 상세 생략
  return <input type='checkbox' {...inputProps} />;
}