TypeScript

Next.js には TypeScript が組み込まれており、create-next-app で新しいプロジェクトを作成する際に必要なパッケージを自動的にインストールし、適切な設定を行います。

既存のプロジェクトに TypeScript を追加するには、ファイルを .ts / .tsx にリネームします。next devnext build を実行すると、必要な依存関係が自動的にインストールされ、推奨設定オプションを含む tsconfig.json ファイルが追加されます。

補足: 既に jsconfig.json ファイルがある場合、古い jsconfig.json から paths コンパイラオプションを新しい tsconfig.json ファイルにコピーし、古い jsconfig.json ファイルを削除してください。

IDE プラグイン

Next.js にはカスタム TypeScript プラグインとタイプチェッカーが含まれており、VSCode や他のコードエディタで高度なタイプチェックとオートコンプリートに使用できます。

VS Code でプラグインを有効にするには:

  1. コマンドパレットを開く (Ctrl/⌘ + Shift + P)
  2. "TypeScript: Select TypeScript Version" を検索
  3. "Use Workspace Version" を選択
TypeScript コマンドパレット

これでファイルを編集する際にカスタムプラグインが有効になります。next build を実行すると、カスタムタイプチェッカーが使用されます。

TypeScript プラグインは以下の点で役立ちます:

  • セグメント設定オプション に無効な値が渡された場合の警告
  • 利用可能なオプションとコンテキスト内ドキュメントの表示
  • 'use client' ディレクティブが正しく使用されているかの確認
  • useState などのクライアントフックが Client Components でのみ使用されているかの確認

🎥 動画: 組み込み TypeScript プラグインについて学ぶ → YouTube (3分)

エンドツーエンドの型安全性

Next.js の App Router には 強化された型安全性 が備わっています。これには以下が含まれます:

  1. データ取得関数とページ間のシリアライゼーション不要: サーバー上のコンポーネント、レイアウト、ページで直接 fetch できます。このデータはクライアント側で React が消費するためにシリアライズ(文字列への変換)する必要が ありません。代わりに、app はデフォルトで Server Components を使用するため、DateMapSet などの値を追加の手順なしで使用できます。以前は、Next.js 固有の型を使用してサーバーとクライアントの境界を手動で型付けする必要がありました。
  2. コンポーネント間のデータフローの合理化: _app が削除されルートレイアウトが採用されたことで、コンポーネントとページ間のデータフローを視覚化しやすくなりました。以前は、個々の pages_app 間のデータフローを型付けするのが難しく、混乱を招くバグが発生する可能性がありました。App Router でデータ取得を同配置することで、この問題は解消されました。

Next.js でのデータ取得 は、データベースやコンテンツプロバイダーの選択を規定することなく、可能な限りエンドツーエンドの型安全性に近づいています。

通常の TypeScript で期待されるように、レスポンスデータを型付けできます。例:

async function getData() {
  const res = await fetch('https://api.example.com/...')
  // 戻り値はシリアライズされません
  // Date、Map、Set などを返せます
  return res.json()
}

export default async function Page() {
  const name = await getData()

  return '...'
}

完全なエンドツーエンドの型安全性には、データベースやコンテンツプロバイダーが TypeScript をサポートしている必要もあります。これは ORM や型安全なクエリビルダーを使用することで実現できます。

next.config.ts の型チェック

next.config.ts で TypeScript を使用し、型をインポートできます。

next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  /* 設定オプションをここに記述 */
}

export default nextConfig

補足: next.config.ts のモジュール解決は現在 CommonJS に限定されています。これにより next.config.ts で ESM のみのパッケージを読み込む際に互換性の問題が発生する可能性があります。

next.config.js ファイルを使用する場合、以下のように JSDoc を使用して IDE で型チェックを追加できます:

next.config.js
// @ts-check

/** @type {import('next').NextConfig} */
const nextConfig = {
  /* 設定オプションをここに記述 */
}

module.exports = nextConfig

静的に型付けされたリンク

Next.js は next/link を使用する際のタイプミスやその他のエラーを防ぐため、リンクを静的に型付けできます。これによりページ間ナビゲーション時の型安全性が向上します。

この機能を利用するには、experimental.typedRoutes を有効にし、プロジェクトで TypeScript を使用している必要があります。

next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  experimental: {
    typedRoutes: true,
  },
}

export default nextConfig

Next.js は .next/types にリンク定義を生成します。この定義にはアプリケーション内のすべての既存ルートに関する情報が含まれており、TypeScript はこれを使用してエディタで無効なリンクについてフィードバックを提供できます。

現在、実験的なサポートには文字列リテラル(動的セグメントを含む)が含まれます。非リテラル文字列の場合、現在は as Routehref を手動でキャストする必要があります:

import type { Route } from 'next';
import Link from 'next/link'

// href が有効なルートの場合、TypeScript エラーは発生しない
<Link href="/about" />
<Link href="/blog/nextjs" />
<Link href={`/blog/${slug}`} />
<Link href={('/blog' + slug) as Route} />

// href が有効なルートでない場合、TypeScript エラーが発生する
<Link href="/aboot" />

next/link をラップするカスタムコンポーネントで href を受け入れるには、ジェネリックを使用します:

import type { Route } from 'next'
import Link from 'next/link'

function Card<T extends string>({ href }: { href: Route<T> | URL }) {
  return (
    <Link href={href}>
      <div>マイカード</div>
    </Link>
  )
}

動作原理

next dev または next build を実行すると、Next.js は .next 内に隠れた .d.ts ファイルを生成します。このファイルにはアプリケーション内のすべての既存ルート(Linkhref 型として有効なすべてのルート)に関する情報が含まれています。この .d.ts ファイルは tsconfig.json に含まれ、TypeScript コンパイラはこの .d.ts をチェックし、エディタで無効なリンクについてフィードバックを提供します。

Async Server Components との使用

TypeScript で async Server Component を使用するには、TypeScript 5.1.3 以上と @types/react 18.2.8 以上を使用していることを確認してください。

古いバージョンの TypeScript を使用している場合、'Promise<Element>' is not a valid JSX element タイプエラーが表示される可能性があります。TypeScript と @types/react の最新バージョンに更新すればこの問題は解決します。

インクリメンタル型チェック

v10.2.1 以降、Next.js は tsconfig.json で有効にした場合のインクリメンタル型チェックをサポートしています。これは大規模なアプリケーションでの型チェック速度向上に役立ちます。

本番環境での TypeScript エラーの無効化

Next.js はプロジェクトに TypeScript エラーがある場合、本番ビルド (next build) を失敗させます。

アプリケーションにエラーがある場合でも Next.js が危険を承知で本番コードを生成するようにしたい場合は、組み込みの型チェックステップを無効にできます。

無効にする場合は、ビルドまたはデプロイプロセスの一部として型チェックを実行していることを確認してください。そうしないと非常に危険です。

next.config.ts を開き、typescript 設定で ignoreBuildErrors オプションを有効にします:

next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  typescript: {
    // !! 警告 !!
    // プロジェクトに型エラーがあっても本番ビルドを成功させる
    // !! 警告 !!
    ignoreBuildErrors: true,
  },
}

export default nextConfig

補足: ビルド前に tsc --noEmit を実行して TypeScript エラーを自分でチェックできます。これは TypeScript エラーをデプロイ前にチェックしたい CI/CD パイプラインで役立ちます。

カスタム型宣言

カスタム型を宣言する必要がある場合、next-env.d.ts を変更したくなるかもしれません。しかし、このファイルは自動生成されるため、加えた変更は上書きされます。代わりに、新しいファイル(例えば new-types.d.ts)を作成し、tsconfig.json で参照してください:

tsconfig.json
{
  "compilerOptions": {
    "skipLibCheck": true
    //...省略...
  },
  "include": [
    "new-types.d.ts",
    "next-env.d.ts",
    ".next/types/**/*.ts",
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": ["node_modules"]
}

バージョン変更点

バージョン変更点
v15.0.0TypeScript プロジェクト向けに next.config.ts サポートが追加されました。
v13.2.0静的に型付けされたリンクがベータで利用可能になりました。
v12.0.0SWC が TypeScript と TSX のコンパイルにデフォルトで使用されるようになり、ビルドが高速化されました。
v10.2.1tsconfig.json で有効にした場合のインクリメンタル型チェック サポートが追加されました。