TypeScriptでReactの型エラーを解決!初心者が知るべき基礎知識
生徒
「Reactでプログラムを書いていると、赤い波線が出てエラーになっちゃいます。TypeScriptの型エラーってどうやって直せばいいんですか?」
先生
「それはTypeScriptが、データの種類が合っていないことを教えてくれている証拠です。型を正しく指定すれば、エラーは消えて安全なプログラムになりますよ。」
生徒
「初心者でも簡単に解決する方法はありますか?」
先生
「もちろんです!まずはエラーのメッセージを読み解くコツから学んでいきましょう。」
1. TypeScriptとReactの型エラーとは何か?
TypeScriptは、プログラムの中で扱うデータに「型」というラベルを付ける仕組みです。例えば、名前なら「文字の型」、年齢なら「数字の型」というように決めます。Reactという道具を使って画面を作るとき、この型が決まっていないと、パソコンは「何を表示すればいいのかわからない」と困ってしまい、赤い波線でエラーを表示します。
プログラミング未経験の方にとって、このエラーは怖く感じるかもしれませんが、実は「このまま動かすと後で壊れるよ」という親切な警告です。エラーを解決することは、パズルのピースを正しい場所に合わせる作業に似ています。まずは落ち着いて、何が原因で怒られているのかを確認することから始めましょう。フロントエンド開発において、このエラー解決能力は非常に重要なスキルとなります。
2. コンポーネントに渡すPropsの型を定義する
Reactでは、部品となる「コンポーネント」に情報を渡すとき、Props(プロップス)という仕組みを使います。TypeScriptでは、このPropsにどのような情報が含まれるかを事前にお知らせする必要があります。これを行わないと「型が存在しません」というエラーが発生します。
まずは、一番基本的な文字列を表示するコンポーネントの書き方を見てみましょう。ここではtypeというキーワードを使って、情報の設計図を作ります。
// 挨拶コンポーネントのための情報の設計図(型)を作る
type WelcomeProps = {
name: string; // 名前は文字ですよ、という指定
};
// 設計図を使ってコンポーネントを作成する
const Welcome = (props: WelcomeProps) => {
return <h1>こんにちは、{props.name}さん!</h1>;
};
このコードでは、nameという項目が必ず「文字列(string)」であることを約束しています。もしここに数字を渡そうとすると、TypeScriptがすぐにエラーを出して守ってくれます。
3. useStateでよくある型エラーの解決策
Reactで画面の内容を書き換えるときに使う「useState」という機能でも、よくエラーが起きます。初期値が空っぽの状態(nullなど)から始めるとき、TypeScriptは「これは後で何が入るかわからない!」と不安になってしまいます。
そんなときは、ジェネリクスという記法を使って、あらかじめ入る可能性のあるデータの種類を教えてあげます。以下の例では、ユーザー名が入るかもしれないし、まだ何も決まっていない(null)かもしれない、という状況を表現しています。
import { useState } from 'react';
const UserProfile = () => {
// 文字列か、あるいは空っぽ(null)のどちらかが入ることを指定
const [userName, setUserName] = useState<string | null>(null);
const login = () => {
setUserName("田中太郎"); // これは文字なのでOK
};
return (
<div>
<p>ユーザー名: {userName}</p>
<button onClick={login}>ログイン</button>
</div>
);
};
このように<型 | 型>と書くことで、「どちらかの型になります」という柔軟な指定が可能になります。これをユニオン型と呼びます。
4. イベントハンドラーの型指定でエラーを防ぐ
ボタンをクリックしたり、入力フォームに文字を打ち込んだりするときの「イベント」にも型が必要です。初心者が一番つまずきやすいのが、この「イベントの型」です。たとえば、入力フォームの内容を受け取る際、(e) => ...と書いただけでは、eが何者なのかTypeScriptには伝わりません。
Reactが用意してくれている専用の型を使うことで、この問題は解決します。以下の例は、テキストボックスの内容が変更されたときに使われる型です。
import React, { useState } from 'react';
const TextInput = () => {
const [text, setText] = useState("");
// e は「入力変更イベント」という型を指定する
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setText(e.target.value);
};
return (
<input type="text" value={text} onChange={handleChange} />
);
};
React.ChangeEvent<HTMLInputElement>という長い名前が出てきましたが、これは「HTMLの入力欄(input)で起きた変化(Change)」という意味です。これをコピペして使うだけでも、多くのエラーを解消できます。
5. 子要素を扱う際のReactNodeの使い方
コンポーネントの中に別の要素を挟み込みたいとき、childrenという特別な名前のPropsを使います。このchildrenには文字だけでなく、太字のタグや他のコンポーネントなど、色々なものが入る可能性があります。そのため、特定の型ではなく、幅広い要素を受け入れられる型を指定する必要があります。
そこで登場するのがReact.ReactNodeです。これは「画面に表示できるものなら何でもOK」という非常に便利な型です。
import React from 'react';
// childrenを受け取るための型定義
type CardProps = {
children: React.ReactNode;
};
const Card = ({ children }: CardProps) => {
return (
<div style={{ border: '1px solid black', padding: '10px' }}>
{children}
</div>
);
};
// 使い方
const App = () => {
return (
<Card>
<p>ここに自由に内容を入れられます</p>
</Card>
);
};
この型を使うことで、「中に何を入れればいいかわからない」というエラーをスマートに回避できます。
6. 配列のデータを扱うときの型定義
ニュースの一覧や商品のリストなど、複数のデータが並んでいる「配列」を扱うときも注意が必要です。単に「配列である」と教えるだけでなく、「何のデータの配列か」まで細かく指定するのがTypeScriptのルールです。
例えば、TODOリストのような項目を扱う場合、一つの項目の形を決めてから、その横に[]を付けることで、その集まりであることを表現します。
type Todo = {
id: number;
task: string;
};
const TodoList = () => {
// Todoの形のデータが並んだ「配列」であることを指定
const [todos, setTodos] = useState<Todo[]>([
{ id: 1, task: "買い物に行く" },
{ id: 2, task: "勉強をする" }
]);
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.task}</li>
))}
</ul>
);
};
もし配列の中身が数字ならnumber[]、文字ならstring[]と書きます。自分たちが作った型でも同様に使えるのが便利なポイントです。
7. 型エラーがどうしても消えないときの奥の手
どうしても原因がわからず、プログラミングが進まなくなってしまうことがあります。特に初心者のうちは、難しい型定義にハマって何時間も悩んでしまうのはもったいないことです。そんなときに一時的に使えるのがanyという型です。
anyは「何でも許す」という意味の魔法の言葉です。これを使うと、TypeScriptはその場所のチェックを諦めるので、エラーが消えます。ただし、これはあくまで「緊急避難」です。使いすぎるとTypeScriptを使う意味がなくなってしまうので、どうしても困ったときにだけ使い、後で詳しい人に聞いたり調べ直したりしましょう。
// どうしても型がわからないときの最終手段(使いすぎ注意!)
const handleMagic = (data: any) => {
console.log(data);
};
まずはエラーを消して画面を動かすことを優先し、少しずつ正しい型に直していくのも上達の近道です。焦らず一歩ずつ進んでいきましょう。
8. エラー文を読み解くための3つのステップ
画面に表示される英語のエラーメッセージは、慣れないうちは呪文のように見えるかもしれません。しかし、実は重要なヒントが書かれています。エラーを解決するために、以下の3つのステップを意識してみてください。
一つ目は、エラーの場所を特定することです。エディタが示している赤い波線の部分をよく見てください。二つ目は、「Property '〇〇' does not exist on type '△△'」という文言を探すことです。これは「△△という型の中に、〇〇なんて項目は見つからないよ」と言っています。三つ目は、期待されている型と実際の型を見比べることです。数字が必要な場所に文字を渡していないか、確認してみましょう。
これらを繰り返すことで、自然と型エラーへの対応力が身についていきます。エラーは失敗ではなく、より良いコードを書くためのガイドラインなのです。Next.jsなどの最新フレームワークでも、この基礎は共通しています。