React TypeScript:useState・useRef・Props の型指定まとめ
React と TypeScript を組み合わせるときに迷いやすい型指定のパターンをまとめます。
useState の型指定
初期値から型が推論される
単純な値は推論に任せて書けます。
const [count, setCount] = useState(0) // number const [name, setName] = useState("") // string const [flag, setFlag] = useState(false) // boolean
null を含む場合は明示が必要
// NG:user の型が null に固定される const [user, setUser] = useState(null) // OK:User | null を明示する type User = { id: number; name: string } const [user, setUser] = useState<User | null>(null)
空配列は型が never[] になる
// NG:items の型が never[] になる const [items, setItems] = useState([]) // OK:型引数を指定する const [items, setItems] = useState<string[]>([]) const [users, setUsers] = useState<User[]>([])
setState を Props に渡す
setState を子コンポーネントに渡すときは Dispatch<SetStateAction<T>> を使います。
import { Dispatch, SetStateAction } from "react" type Props = { setCount: Dispatch<SetStateAction<number>> } function Child({ setCount }: Props) { return <button onClick={() => setCount((n) => n + 1)}>+1</button> }
useRef の型指定
DOM 要素を参照する
DOM を参照する場合は要素の型を指定します。初期値は null を渡します。
// input 要素 const inputRef = useRef<HTMLInputElement>(null) // div 要素 const divRef = useRef<HTMLDivElement>(null) // button 要素 const btnRef = useRef<HTMLButtonElement>(null)
ref.current は null チェックが必要
DOM がマウントされる前は current が null のため、オプショナルチェーン(?.)を使います。
const inputRef = useRef<HTMLInputElement>(null) const handleFocus = () => { inputRef.current?.focus() // null の場合は何もしない inputRef.current?.select() } return <input ref={inputRef} />
ミュータブルな値を保持する(再レンダリングしない)
タイマー ID などレンダリングに影響しない値を保持する場合は初期値に値を渡します。このとき current は null になりません。
// タイマー ID の保持 const timerRef = useRef<number>(0) const start = () => { timerRef.current = window.setInterval(() => { // ... }, 1000) } const stop = () => { clearInterval(timerRef.current) }
DOM 参照(初期値 null)とミュータブル値(初期値あり)で current の型が変わります。
Props の型指定
children
import { ReactNode } from "react" type Props = { children: ReactNode // テキスト・要素・配列など何でも受け取れる } // JSX.Element だと文字列などを渡せないため ReactNode が汎用的
イベントハンドラ
type Props = { onClick: () => void onChange: (e: React.ChangeEvent<HTMLInputElement>) => void onSubmit: (e: React.FormEvent<HTMLFormElement>) => void onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void }
style
インラインスタイルを Props で渡す場合は React.CSSProperties を使います。
type Props = { style?: React.CSSProperties } // 使う側 <MyComponent style={{ color: "red", fontSize: 14 }} />
オプショナルな Props
? を付けるとオプショナルになります。
type Props = { label: string // 必須 placeholder?: string // 省略可能 disabled?: boolean // 省略可能(デフォルト undefined) }
よく使う型まとめ
| 用途 | 型 |
|---|---|
useState の null 許容 |
useState<T | null>(null) |
setState を Props に渡す |
Dispatch<SetStateAction<T>> |
| input の DOM 参照 | useRef<HTMLInputElement>(null) |
| div の DOM 参照 | useRef<HTMLDivElement>(null) |
| children | ReactNode |
| input の onChange | React.ChangeEvent<HTMLInputElement> |
| インラインスタイル | React.CSSProperties |
| クリックイベント | React.MouseEvent<HTMLButtonElement> |
TypeScript のジェネリクス全般については「TypeScript ジェネリクス入門:<T> の基本と型制約の書き方」も参照してください。