props での交差型(&)の扱いを勘違いしていた

37516 ワード

はじめに

汎用的なコンポーネントを作る際に、交差型の使い方を間違っていたことに最近気づいたので記事にしました。

結論

あるコンポーネントをもとに props の型を拡張する際は

type InputProps = ComponentProps<typeof Input>
type Props = InputProps & {
    rounded: boolean
}

export const MyInput: FC<Props> = ({ rounded, ...attrs }) => {}

こうではなく

type Merge<T, U> = Omit<T, keyof U> & U

type InputProps = ComponentProps<typeof Input>
type Props = Merge<InputProps, {
    rounded: boolean;
}>

export const MyInput: FC<Props> = ({ rounded, ...attrs }) => {}

こうしましょうという記事です。

React というより TypeScript の交差型に関わる話なので、交差型を正しく理解している方には読む必要のない記事かと思います。
(私のように)交差型が型をマージするものだと勘違いしていた方の参考になればと思います。

余談: React.ComponentProps について

汎用的なコンポーネントは pa のようなプリミティブな要素と同等に扱えるべきです。
React.ComponentProps を使うことで、プリミティブな要素に渡せる props の型を定義することが可能です。

import type { ComponentProps, FC } from "react";

const style = {};

type Props = ComponentProps<"input">; // <input /> に渡せる props の型

export const Input: FC<Props> = ({ ...attrs }) => {
  return <input {...attrs} style={style} />;
};
// 使う側で <input /> と同等の props を渡せるreturn (
    <Input
      type="text"
      placeholder="username"
      value="username"
    />
  )


これについては Takepepe さんの記事で大変分かりやすくまとめられているので、詳しく知りたい方はこちらを御覧ください。