Hタグごとにコンポーネントを作成する際に型定義をどうしていいものか悩みました…。
思考した内容をまとめましたのでコンポーネントを作成する際の参考にしていただけると幸いです!
Hタグはasを利用してポリモフィック的に作るべきか?
Hタグはh1からh6までタグがあります。
asを利用することで1つのコンポーネントに複数の役割を与えられます!
import { ReactNode } from 'react';
type Props = {
as: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
children: string;
};
const Heading = ({ as: Tag, children }: Props) => {
return (
<Tag>{children}</Tag>
)
};
export default Heading;
hタグだけだと決めていればリテラル型で定義するのも良いかと考えています!
ただ、Hタグをポリモフィックなコンポーネントとして定義するよりも、別々に分けて定義する方が良いのでは?というのが私の考えです!
例に出したコンポーネントは、スタイルのないコンポーネントですが、h1〜h6までのスタイルをどれだけシンプルに書けたとしても見づらい状態になる可能性が高いと考えています。
h3タグのデザインを修正すると他のhタグにも影響がでる可能性を及ぼす可能性が出るので、コンポーネントは分ける方が良いのでは?と考えております。
ポリモフィックコンポーネントについての説明は別の記事で紹介していますのでよければ確認してください!
Hタグの型定義はどうするべきか?
例えば下記のようなコンポーネントを実装したとします。
import { FC } from 'react';
type Props = {
children: React.ReactNode;
} & JSX.IntrinsicElements['h1'];
const Heading: FC<Props> = ({ children }) => {
return <h1>{children}</h1>;
};
export default Heading;
JSX.IntrinsicElements['h1']
で拡張してみました。
本来h1タグに付与できない属性を付与された場合にエラーを出したいです!
このままだと任意のclass
やstyle
を付与された場合も設定さえあれば受け取れてしまいます…
統一したかったはずのデザインを自由に変更できるHeadingコンポーネントになるのは避けるためにOmitで一部型を除いた新しい型を作りたいと思います。
import { FC } from 'react';
type exclusionOptional = 'className' | 'style';
type Props = {
children: React.ReactNode;
- } & JSX.IntrinsicElements['h1'];
+ } & Omit<JSX.IntrinsicElements['h1'], exclusionOptional>;
const Heading: FC<Props> = ({ children }) => {
return <h1>{children}</h1>;
};
export default Heading;
TypeScriptが用意してくれているinterfaceを利用して自前で定義しなくてもOmit
などを利用してさまざまな型を作れます。
Omit
については別の記事で紹介していますのでよろしければご覧ください!
【Hタグコンポーネントを作る時の型定義について考えてみる】まとめ
ついついまとめてしまいたくなるのが心情ですが、時には分けるという選択も良いのでは?と考えています。
影響範囲を小さくすることで変更容易性を担保することになるのでコンポーネントが増えることよりも小さく、複雑度が低い状況を作ることの方が長くサイトを運用するという観点では大切な場合もあると考えます!
作ったコンポーネントを利用する時のことを考えるとpropsが多くなればなるほど覚えるが大変です…
使う側の観点と実装者の両方の観点から長く安定的に運用できるコンポーネントを作れるように引き続き精進します!