型の定義でComponentPropsWithoutRefとJSX.IntrinsicElementsというものがあることを知りました。
違いがわからなかったので調べてみました。
ComponentPropsWithoutRefとは?
指定したHTML要素のPropsの型を取得します。
この型は、HTML要素の全てのネイティブ属性をPropsとして取得します。
JSX.IntrinsicElementsとは?
Reactの型定義の一部で、HTML要素のPropsの型を定義するために使用します。
2つの型の違いは?
ComponentPropsWithoutRefは、型を取得するのに対して、JSX.IntrinsicElementsは、型を定義します。
は?って感じですよね…私も同じ感情を持ちました…
具体的な例で確認してみたいと思います。
例えば下記のような書き方だとエラーになります。
export interface Props extends JSX.IntrinsicElements['li'] {
specialProp?: string;
}
下記の記述方法だとエラーになりません。
export interface Props extends ComponentPropsWithoutRef<'li'> {
specialProp?: string;
}
エラーの内容は下記のとおりです。
インターフェイスが拡張するのは、オプションの型引数が指定された識別子/完全修飾名のみです。
TypeScriptの制限で、typeは直接的に拡張できるのに対してinterfaceはできないとのことです。
エラーを出さずにJSX.IntrinsicElements['li']を利用する方法
JSX.IntrinsicElements['li']を使いつつ、エラーを出さないで拡張した型を作る方法を紹介します。
type listItemProps = JSX.IntrinsicElements['li'];
export interface Props extends listItemProps {
specialProp?: string;
}
一度type(Type Alias)を利用して、JSX.IntrinsicElements['li']の方に名前をつけます。
その上でextendsするとエラーは発生しません。
interfaceを使わずtypeを利用するとJSXの記述でも拡張ができる
type Props = JSX.IntrinsicElements["li"] & {
hogehoge: string
}
interfaceではなく、type(Type Alias)を利用します。
&を利用して型を拡張することで解決策①よりもシンプルに書けます。
【ComponentPropsとJSX.IntrinsicElementsの違い】まとめ
まだ紐解けてない部分はありますが、typeを利用するかinterfaceを利用するかで選択が変わりそうだと思います。
一般的にはtypeは柔軟でinterfaceはオブジェクトの型を定義する時に用いられるようです。
適切な型定義の方法を選べるようになるために引き続き精進します。