useRefとTypeScript - LegacyRef<HTMLDivElement>への型エラー解決
ReactのuseRef
フックをTypeScriptで使用する際、LegacyRef<HTMLDivElement>
への割り当てができないというエラーに遭遇することがあります。この問題は、適切な型指定とReactのrefシステムの理解が不足している場合に発生します。
問題の特定
エラーメッセージ「not assignable to type 'LegacyRef<HTMLDivElement> | undefined'」は、主に以下の原因で発生します:
- 間違ったHTML要素型の指定
null
初期化の欠落- ジェネリック型とコンポーネント期待型の不一致
解決策
1. 正しいHTML要素型の使用
HTMLElement
ではなく、より具体的な要素型を使用する必要があります。
// ❌ 間違った例
const ref = useRef<HTMLElement>(null);
// ✅ 正しい例
const divRef = useRef<HTMLDivElement>(null);
const buttonRef = useRef<HTMLButtonElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
const svgRef = useRef<SVGSVGElement>(null);
const iframeRef = useRef<HTMLIFrameElement>(null);
2. nullでの初期化
useRef
は必ずnull
で初期化する必要があります。
// ❌ 間違った例
const ref = useRef<HTMLDivElement>();
// ✅ 正しい例
const ref = useRef<HTMLDivElement>(null);
3. 完全なコード例
import React, { useRef } from 'react';
function Test() {
const node = useRef<HTMLDivElement>(null);
if (node.current) {
// 安全にプロパティにアクセス
console.log(node.current.clientWidth);
}
return <div ref={node}>コンテンツ</div>;
}
カスタムフックでの汎用的な使用
複数の要素タイプで再利用可能なカスタムフックを作成する場合は、ジェネリック型を使用します。
const useCustomHook = <T extends HTMLElement = HTMLDivElement>() => {
const elementRef = useRef<T>(null);
// カスタムロジック
React.useEffect(() => {
if (elementRef.current) {
// 要素に対する操作
}
}, []);
return elementRef;
};
// 使用例
function MyComponent() {
const buttonRef = useCustomHook<HTMLButtonElement>();
const divRef = useCustomHook<HTMLDivElement>();
return (
<>
<button ref={buttonRef}>ボタン</button>
<div ref={divRef}>コンテンツ</div>
</>
);
}
注意
as unknown as ...
のような型アサーションは、型システムを迂回するため避けるべきです。代わりに適切な型指定を行いましょう。
型システムの理解
Reactのrefシステムは以下の型定義を持っています:
interface RefObject<T> {
readonly current: T | null;
}
type LegacyRef<T> = RefObject<T> | ((instance: T | null) => void) | null;
useRef
は渡される初期値によって異なる型を返します:
useRef<T>(initialValue: T)
:MutableRefObject<T>
useRef<T>(initialValue: T | null)
:RefObject<T>
useRef<T = undefined>()
:MutableRefObject<T | undefined>
まとめ
useRef
のTypeScriptエラーを解決するには:
- 具体的なHTML要素型(
HTMLDivElement
など)を使用する - 必ず
null
で初期化する - ジェネリック型を使用して再利用可能なコンポーネントを作成する
- 型アサーションではなく適切な型指定を行う
これらの原則に従うことで、型安全でメンテナンスしやすいReactコンポーネントを作成できます。