【テクニカル・上級編】 Intersection Typesを用いたPropsの合成 – React実践ガイド

凡庸なProps管理からの脱却:Intersection Typesで築く堅牢なコンポーネント設計

Reactアプリケーションの規模が巨大化するにつれ、最も我々を苦しめるのは「Propsの型定義の腐敗」です。特に、HTMLの標準要素をラップした「高機能なコンポーネント」を作る際、`any`の誘惑や、無計画なオプショナルプロパティの乱用で型定義がスパゲッティ化している現場を数多く見てきました。

今日は、TypeScriptの `Intersection Types(&演算子)` を駆使し、既存のHTML属性を殺さずにカスタムPropsを安全に合成する、アーキテクトレベルの「型安全なラップ術」について掘り下げます。

—

なぜ単なるインターフェース継承では足りないのか

多くのエンジニアは、まず以下のようなコードを書きます。

interface ButtonProps {
variant: ‘primary’ | ‘secondary’;
onClick: () => void;
// ここに標準のHTML属性を一つ一つ手書きして、地獄を見る
}

ここで `HTMLButtonElement` の属性を全て含めようとして `extends` を使うのは一見正解ですが、実は罠があります。`React.ButtonHTMLAttributes` を継承すると、我々が定義した `onClick` のシグネチャと標準の `onClick` が衝突し、型エラーの温床になるのです。

これを解決するのが、Intersection Typesによる「型合成」と「Omitによる排除」の組み合わせです。

—

実践:型を合成し、制御を奪い返す

以下は、標準の `button` 要素の機能を保持しつつ、我々のカスタムロジックを型安全に注入する設計例です。

import React from ‘react’;

// 1. 衝突を避けるためのOmitとIntersectionの組み合わせ
// 標準のHTML属性から、今回自前で制御したいPropsを間引く
type BaseProps = Omit, ‘onClick’ | ‘className’>;

interface CustomButtonProps extends BaseProps {
variant?: ‘primary’ | ‘secondary’;
// 型を上書きして厳格化する
onClick: (event: React.MouseEvent) => void;
// class名も強制的にコンポーネントの責務にするなら、ここで独自定義する
className?: string;
}

export const SmartButton: React.FC = ({
variant = ‘primary’,
onClick,
className = ”,
…rest // 残りのHTML属性を一括で受け取る「型安全なバケツ」
}) => {
// ここでDOMへ渡すpropsを分離することで、Reactのレンダリング負荷を軽減し、
// 不要な属性がDOMに混入する(Reactの警告)を防ぐ
return (

コメント

タイトルとURLをコピーしました