【React × TypeScript】HTML属性の型情報のインポート方法
ReactとTypeScriptでカスタムコンポーネントを作っていた際に、通常のHTMLタグの属性の型をどのように持ってくればいいんだろうと思ったので、調べたことをまとめました。
結論:React.ComponentPropsWithoutRef
※もしくは React.ComponentPropsWithRef
以下ように書くことができます。
import React from 'react' type ButtonProps = React.ComponentPropsWithoutRef<'button'>
他の方法として、
ComponentProps
IntrinsicElements
[Element]HTMLAttributes
HTMLProps
HTMLAttributes
を使った実装があるみたいですが、なぜこれらではなく ComponentPropsWithoutRef
を使うのか、という理由が下記で語られています。
react-typescript-cheatsheet.netlify.app
以下は上記の意訳になります。
ComponentProps
ComponentPropsWithRef
の代わりに ComponentProps
を使うこともできるが、
コンポーネントの参照(ref) が転送されるかどうかを明示的にすることをおすすめします。
JSX.IntrinsicElements
と React.[Element]HTMLAttributes
他に少なくとも2つの同等の方法がありますが、より冗長です。
// 方法 1: JSX.IntrinsicElements type btnType = JSX.IntrinsicElements["button"]; // インライン化できない or エラーになる export interface ButtonProps extends btnType {} // etc // 方法 2: React.[Element]HTMLAttributes export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>
ComponentPropsの実装 を見ると、これは巧妙なラッパーになっていることが分かります。一方、2番目の方法はよく分からない命名/大文字の特殊なインターフェースに依存しています。
最終的には、TS特有の専門用語が少なく、使い勝手の良いComponentPropsの方法を選びました。しかし、お望みであればどちらの方法でも問題ないでしょう。
React.HTMLProps
や React.HTMLAttributes
は絶対によくありません。
React.HTMLProps
を使用するとこうなります。
export interface ButtonProps extends React.HTMLProps<HTMLButtonElement> { specialProp: string; } export function Button(props: ButtonProps) { const { specialProp, ...rest } = props; // エラー: 'string' 型 は '"button" | "submit" | "reset" | undefined' 型に割り当てることができません。 return <button {...rest} />; }
中で AllHTMLAttributes
を使用しているため 広すぎる文字列型を推論してしまうのです。
React.HTMLAttributes
を使用すると、このようになります。
export interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement> { /* etc */ } // usage function App() { // プロパティ 'type' が 'IntrinsicAttributes & ButtonProps' に存在しません。 return <Button type="submit"> text </Button>; }