Next.js×TypeScriptでgetStaticPropsとgetServerSidePropsに型をつける方法を徹底解説!
生徒
「Next.jsでデータを取得する getStaticProps や getServerSideProps を使いたいのですが、TypeScriptだと型エラーが出て困っています。」
先生
「それらはNext.js特有の関数ですね。TypeScriptを使うと、データの形をあらかじめ決めておくことができるので、開発がとてもスムーズになりますよ。」
生徒
「型をつけることで、具体的にどんなメリットがあるのでしょうか?」
先生
「一番の利点は、中身が何かわからないという不安がなくなることです。それでは、基本的な付け方から順番に学習していきましょう!」
1. getStaticPropsとgetServerSidePropsとは?
まず、型をつける前にこれらが何をしているのかを簡単におさらいしましょう。Next.jsという便利な道具箱の中には、画面を表示する前にあらかじめデータを準備しておく仕組みが備わっています。
getStaticProps(げっと・すたてぃっく・ぷろっぷす)は、家を建てる前に材料をすべて揃えておくようなものです。サイトを作る瞬間に一度だけデータを取ってきて、ずっとそのデータを使います。表示が非常に速いのが特徴です。
getServerSideProps(げっと・さーばー・さいど・ぷろっぷす)は、注文を受けてから料理を作るレストランのようなものです。誰かがサイトにアクセスするたびに、最新のデータを取ってきて画面に反映させます。常に最新の情報が必要な時に使います。
これらを使う際、プログラム側は「どんな種類のデータが届くのか」を知りたがります。そこで役立つのがTypeScript(タイプスクリプト)による「型定義」です。型とは、データの入れ物の形を指定するルールのことです。
2. なぜ型定義が必要なのか
プログラミング未経験の方にとって、「型」という言葉は聞き慣れないかもしれません。例えば、冷蔵庫の中に「卵」を入れるケースがあるとします。このとき、ケースの形が卵専用であれば、間違って大きなスイカを入れようとしたときに「入らないよ!」と気づくことができます。これがプログラミングにおける型の役割です。
TypeScriptを使わずにNext.jsでデータをやり取りすると、画面を表示する部品(コンポーネント)は、どんなデータが送られてくるか正確に把握できません。数字が届くと思っていたのに文字が届いてしまった場合、プログラムは途中で止まってしまいます。これを防ぐために、あらかじめ「この関数はこういう形のデータを返しますよ」と宣言しておく必要があるのです。
型をしっかりと定義することで、入力ミスや勘違いをパソコンが自動で教えてくれるようになります。これは、初心者がバグを見つけるための強力な味方になります。
3. 基本的な型定義の書き方
まずは、Next.jsが用意してくれている「専用の型」を使う方法を学びましょう。Next.jsには、最初から getStaticProps や getServerSideProps のために作られた型が存在します。これを使うのが一番確実で簡単です。
以下のコード例では、非常にシンプルなニュースの見出しを表示する場合を想定しています。データの種類を定義する「type」というキーワードを使って、どのような情報が必要かを書き出していきます。
import { GetStaticProps, NextPage } from 'next';
// データの形を定義します(ニュースの見出しと日付)
type Props = {
title: string;
date: string;
};
// getStaticPropsに型を適用します
export const getStaticProps: GetStaticProps<Props> = async () => {
return {
props: {
title: "初めてのTypeScript学習",
date: "2026-05-11"
}
};
};
// 画面を表示する部品(コンポーネント)にも型を渡します
const Page: NextPage<Props> = ({ title, date }) => {
return (
<div>
<h1>{title}</h1>
<p>日付: {date}</p>
</div>
);
};
export default Page;
このコードの中で、GetStaticProps<Props> という記述があります。これは「この関数はPropsという形のデータを扱う getStaticProps ですよ」と指定している部分です。これにより、中身のデータが間違っていたらエラーで教えてくれるようになります。
4. getServerSidePropsでの実践的な型定義
次に、アクセスするたびに内容が変わる getServerSideProps の場合を見てみましょう。書き方は getStaticProps とほとんど同じですが、使う型の名前が GetServerSideProps に変わります。
例えば、現在ログインしているユーザーの名前を表示するような処理を考えてみましょう。インターネット上からデータを取ってくる「非同期処理(async/await)」という仕組みを使いますが、ここでも型定義が力を発揮します。
import { GetServerSideProps, NextPage } from 'next';
// ユーザー情報の型を定義
type UserProps = {
userName: string;
loginTime: string;
};
export const getServerSideProps: GetServerSideProps<UserProps> = async (context) => {
// 本来はここでデータベースなどからデータを取得します
const name = "田中太郎";
const now = new Date().toLocaleTimeString();
return {
props: {
userName: name,
loginTime: now
}
};
};
const UserPage: NextPage<UserProps> = ({ userName, loginTime }) => {
return (
<div>
<h2>ログイン情報</h2>
<p>ユーザー名: {userName}</p>
<p>アクセス時刻: {loginTime}</p>
</div>
);
};
export default UserPage;
ここで重要なのは、context という引数です。これを使うことで、今どんな人がアクセスしてきたのか、どんなURLから来たのかといった情報を知ることができます。これにも型がついているので、ドット(.)を打つだけでどんな情報が使えるか候補が出てくるようになり、初心者でも迷わず操作できます。
5. InferGetStaticPropsTypeを使った効率的な方法
これまで紹介した方法は、自分で型を二回書く必要がありました(関数の型と、画面部品の型)。しかし、Next.jsには「関数から自動的に型を推論して抽出する」というさらに便利な方法があります。それが InferGetStaticPropsType です。
これを使うと、getStaticProps が返した値の形をそのまま画面部品の型として利用できるため、型を書き直す手間が省けます。記述の重複がなくなるので、コードがすっきりします。
import { GetStaticProps, InferGetStaticPropsType } from 'next';
// 取得したいデータの型
type Post = {
id: number;
content: string;
};
export const getStaticProps: GetStaticProps<{ post: Post }> = async () => {
const post = { id: 1, content: "TypeScriptは難しくない!" };
return {
props: { post }
};
};
// 関数から型を自動で取り出して適用する
type PageProps = InferGetStaticPropsType<typeof getStaticProps>;
const PostPage = ({ post }: PageProps) => {
return (
<article>
<p>ID: {post.id}</p>
<p>内容: {post.content}</p>
</article>
);
};
export default PostPage;
この「推論」という機能は、TypeScriptのとても賢い部分です。「中身を見て判断する」という自動化のおかげで、人間が細かく指示を出さなくても正確なプログラムが組めるようになります。
6. 配列のデータを扱う場合の型指定
実際の開発では、データは一つだけでなく、リスト(配列)として届くことがよくあります。例えば、ブログの記事一覧や商品のリストなどです。TypeScriptでは、配列の型を 型名[] という形で表現します。
初心者の方がよくつまずくのが、この配列の扱いです。「一つ分の形」をまず決めて、それを「束ねた形」を指定するという二段構えで考えると理解しやすくなります。
import { GetStaticProps, NextPage } from 'next';
// 商品一つの形
type Product = {
name: string;
price: number;
};
// 画面に渡すデータの形(商品のリスト)
type ListProps = {
products: Product[];
};
export const getStaticProps: GetStaticProps<ListProps> = async () => {
const productList = [
{ name: "りんご", price: 150 },
{ name: "みかん", price: 100 },
{ name: "バナナ", price: 200 }
];
return {
props: {
products: productList
}
};
};
const ProductListPage: NextPage<ListProps> = ({ products }) => {
return (
<ul>
{products.map((item, index) => (
<li key={index}>
{item.name}: {item.price}円
</li>
))}
</ul>
);
};
export default ProductListPage;
プログラムの中で map という命令が出てきましたが、これはリストの中身を一つずつ順番に取り出して処理するためのものです。型がしっかりついているので、item.name と書いたときに「それは文字列ですよ」とパソコンが認識してくれます。これにより、間違えて計算に使おうとしたりするミスを防げます。
7. エラーを防ぐための「オプショナル」な型
データの中には、あったりなかったりするものがあります。例えば、ユーザーの「プロフィール画像」は設定していない人もいますよね。そのような場合に、無理やり「必ずある」と型を決めてしまうと、データがないときにプログラムが壊れてしまいます。
そんな時に使うのが、ハテナマークを使った ?(オプショナルプロパティ)です。これをつけておくと、「このデータは空っぽの可能性もあるよ」とTypeScriptに伝えることができます。
安全なプログラムを作るためには、この「ないかもしれない」という可能性を考慮することが非常に重要です。初心者のうちはすべてが揃っている前提で作りがちですが、実務ではこの考慮がプロの仕事の分かれ目になります。
8. 開発環境のサポートを最大限に活かす
TypeScriptを使う最大の楽しみは、コードを書いている最中にリアルタイムでアドバイスがもらえることです。Visual Studio Codeなどのエディタを使っていると、型を定義した瞬間に、次に何を書けばいいのかを予測して表示してくれるようになります。
これは、英語の辞書を引きながら作文するのではなく、隣で詳しい人が「次はこう書くんだよ」と教えてくれているような感覚です。未経験の方こそ、このサポート機能があるTypeScriptを使うべきだと言えます。最初は覚えることが多いと感じるかもしれませんが、慣れてくると型がないプログラミングが怖くなるほど、安心感を与えてくれます。
まずは、今回紹介した GetStaticProps や GetServerSideProps の型を真似して書いてみることから始めてみましょう。何度も繰り返すうちに、データの形を定義するという考え方が自然と身についていくはずです。