logo

Reactのコンポーネント設計 - React.ComponentProps 型が便利

2025-12-04
a month ago

開発環境

  • react 19.2.0
  • react-dom 19.2.0

前提

React のコンポーネント設計では、HTML 要素や既存コンポーネントの Props を安全かつ効率的に引き継ぎたい場面が多くあります。

その際、手で Props をすべて再定義するのは非効率で、保守性も低くなります。

これを解決する技法として有効なのが React.ComponentProps を使う設計です。

shadcn/ui のコンポーネントも同じ考え方を採用しており、現代的な UI コンポーネント設計における重要なパターンになっています。

本題

1. React.ComponentProps の概要

React.ComponentProps<"button"> のように指定すると、その要素が本来受け取るすべての Props(イベント、属性、ARIA、ref など)をそのまま型として利用できます。

type ButtonProps = React.ComponentProps<"button">;

この仕組みによって、React コンポーネントで HTML 属性を再記述する必要がなくなります。

2. shadcn/ui が採用している Props 設計

shadcn/ui のコンポーネントでは、次の 2 点を組み合わせた設計になっています。

  • React.ComponentProps<"button">
  • VariantProps<typeof buttonVariants>

実際の Button コンポーネントは以下のような構造です。

function Button({
  className,
  variant,
  size,
  asChild = false,
  ...props
}: React.ComponentProps<"button"> &
  VariantProps<typeof buttonVariants> & {
    asChild?: boolean
  }) {
  const Comp = asChild ? Slot : "button"

  return (
    <Comp
      data-slot="button"
      className={cn(buttonVariants({ variant, size, className }))}
      {...props}
    />
  )
}

この設計により、HTML ボタン本来の属性(onClick, disabled, type, aria-* など)を余さず受け継ぎつつ、UI ライブラリ独自のバリアント機能を組み合わせられます。

3. React.ComponentProps を使うメリット

👉 3-1. コード量が減らせる

onClick, disabled, type などを手動で列挙する必要がなくなるため、Props 定義が最小限で済みます。

// 冗長: 自前で列挙
type Props = {
  onClick?: () => void
  disabled?: boolean
  type?: "button" | "submit"
}
// 省略できる
type Props = React.ComponentProps<"button">;


👉 3-2. 型の追従が自動化

HTML 要素側に新しい属性が追加されても、そのまま使えるため更新コストがほぼゼロになります。


👉 3-3. 独自定義との併用が簡単

shadcn/ui のように VariantProps と組み合わせると、以下を同時に満たせます。

  • HTML 要素の完全な互換性
  • UI デザインシステムとしてのバリアント管理
  • Props の自然な拡張

React ComponentProps が基盤となっていることで、拡張性と保守性が高い設計になります。


👉 3-4. 「薄いラッパー」が作りやすい

HTML ボタンを装飾しただけのコンポーネントのように、元の DOM 属性をそのまま渡したいケースは多いです。 その際、Props の再定義が不要で、使い心地も素の HTML と一致するため、ラッパーコンポーネントを気軽に作れます。

さいごに

React.ComponentProps は、HTML 要素や既存コンポーネントの Props を安全に継承できる強力なユーティリティです。 shadcn/ui のような洗練されたコンポーネント設計にも採用されており、コード量削減・保守性向上・拡張性の改善に大きく寄与します。

コンポーネント設計の基礎として、ぜひ日常的に活用したいテクニックです。

参照