TypeScriptで型指定をすることで開発中に発生するエラーやバグを事前に防ぐことができ、より安全で信頼性の高いコードを作成することができます。
今回は、TypeScriptを使ってReactアプリケーションを開発するときのchildrenとpropsに型を指定する方法を解説していきます。
実際のコード例や具体的な手順を交えながら一般的なベストプラクティスを共有しますので初心者には役立つ情報となることでしょう。
React開発でTypeScriptを使用している方はもちろん、まだTypeScriptに慣れていない方も、この記事を通じてReactアプリケーションの品質向上に貢献できる知識を得ることができます。
また動画もあるので必要に応じて活用してください。
ReactのchildrenにおけるTypeScriptの書き方
まずは以下のようなコンポーネントを準備します。
import "./App.css";
import Heading from "./screens/ts-counter/components/Heading";
function App() {
return (
<>
<Heading title="こちらはタイトルです。" />
</>
);
}
export default App;
import React from "react";
type HeadingProps = { title: string };
const Heading = ({ title }: HeadingProps) => {
return <div>{title}</div>;
};
export default Heading;
Heading.tsxにpropsで文字列を渡しているので画面上では上図のようなテキストが表示されています。
さらに新しくファイルを新規作成します。
import React from "react";
const Section = () => {
return (
<div>
Section
</div>
);
};
export default Section;
このSection.tsxをchildrenとして扱うコンポーネントにしたいとします。
その場合、親コンポーネントのApp.tsxでは以下のように読み込みます。
import "./App.css";
import Heading from "./screens/ts-counter/components/Heading";
// ここを追加
import Section from "./screens/ts-counter/components/Section";
function App() {
return (
<>
<Heading title="こちらはタイトルです。" />
{/* ここを追加 */}
<Section>ここがチルドレンです。</Section>
</>
);
}
export default App;
通常のコンポーネントだと</>の書き方ですが、childrenのコンポーネントを読み込みたい場合はHTMLのように<></>で書きます。
開始タグと閉じタグの間に書いたテキストがchildrenというプロパティ名でpropsとして渡すことができるようになります。
childrenをSection.tsxで受け取る際にはTypeScriptなので型が必要になります。
今回渡しているchildrenの型は文字列なのでstringになります。
import React from "react";
// ここを追加
type SectionProps = {
children: string;
};
// ここを追加
const Section = ({ children }: SectionProps) => {
return (
<section>
<p>{children}</p>
</section>
);
};
export default Section;
またSection.tsxにchildren以外のpropsでtitleというテキストを渡すようにしたい場合は以下のようにします。
import "./App.css";
import Heading from "./screens/ts-counter/components/Heading";
import Section from "./screens/ts-counter/components/Section";
function App() {
return (
<>
<Heading title="こちらはタイトルです。" />
{/* ここを変更 */}
<Section title="新しいテキストです。">ここがチルドレンです。</Section>
</>
);
}
export default App;
import React from "react";
// ここを変更
type SectionProps = {
title: string;
children: string;
};
// ここを変更
const Section = ({ children, title }: SectionProps) => {
return (
<section>
<h1>{title}</h1>
<p>{children}</p>
</section>
);
};
export default Section;
Section.tsxの内容もpropsにして画面に表示することができましたね。
childrenもpropsの一部なのでpropsの書き方がわかっていればchildrenも同じような理解になると思います。
ちなみにコンポーネントをchildrenにして表現するときはどうすれば良いのでしょうか?
App.tsxを新しく作り直します。
Text.tsxというコンポーネントにテキストをchildrenとして渡します。
import React from 'react';
import Text from './components/Text';
const App = () => {
return (
<div>
<Text>チルドレンです</Text>
</div>
);
};
export default App;
import React from 'react';
type TextProps = {
children: string;
};
const Text = (props: TextProps) => {
return <div>{props.children}</div>;
};
export default Text;
ここまでは先ほどと同じ考え方ですがApp.tsxでText.jsを別のコンポーネントであるWrapper.tsxというもので囲んでみます。
Wrapper.tsxからするとText.tsx自体がchildrenになっているわけですね。
import React from 'react';
import Text from './components/Text';
const App = () => {
return (
<div>
{/* ここを変更 */}
<Wrapper>
<Text>入れ子のチルドレンです。</Text>
</Wrapper>
</div>
);
};
export default App;
Wrapper.tsxについてはコンポーネントをchildrenとして持つということでReat.ReactNodeという型を指定します。
import React from 'react';
type WrapperProps = {
children: React.ReactNode;
};
const Wrapper = (props: WrapperProps) => {
return <div>{props.children}</div>;
};
export default Wrapper;
childrenなのでstringとしがちですが、コンポーネントファイルは単なる文字列ではありませんのでReact.ReactNodeというものを指定することを覚えておいてください。
ReactのカウンターをchildrenとTypeScriptで作ってみる
もう少し実務的なコードを書いてみましょう。
Reactの初学者向けの教材でよく使用されるカウンターをchildrenを使った書き方でつくってみます。
import "./App.css";
// ここを変更
import Counter from "./screens/ts-counter/Counter";
import { useState } from "react";
function App() {
// ここを追加
const [count, setCount] = useState<number>(0);
return (
<>
{/* ここを変更 */}
<Counter setCount={setCount}>{count}</Counter>
</>
);
}
export default App;
import React, { useState } from "react";
type CounterProps = {
setCount: React.Dispatch<React.SetStateAction<number>>;
children: React.ReactNode;
};
const Counter = ({ setCount, children }: CounterProps) => {
return (
<div>
<h1>{children}</h1>
<button onClick={() => setCount((current) => current + 1)}>+</button>
<button onClick={() => setCount((current) => current - 1)}>-</button>
</div>
);
};
export default Counter;
childrenとして使用するのをカウントの結果にしています。
もちろんcount={count}のように新しくpropsのプロパティを作って渡しても良いのですが、今回はchildrenとして渡しています。
count自体は数字(number型)ですがchildrenとして使用するため、TypeScriptはReact.ReactNodeの方になりました。
とはいえ正常に動作しているので書き方を変えても問題ないことがわかります。
またchildrenとは違う話ですが、App.tsx側でcountを更新するためのsetCountという関数をpropsとして渡しました。
今回のsetCountの型は「React.Dispatch<React.SetStateAction<number>>」となります。
型名が随分と長いですが決まっているものなので覚えるか都度調べることになるでしょう。
VSCODEの補完機能でsetCountをマウスホバーすると型名が表示されるので、そちらから把握しても良いと思います。
最初はJavaScriptと少し書き方が違うので戸惑いますが慣れるとなんて事ないので練習してみてください。
また今回参考にした本は以下になりますので良ければどうぞ。