TypeScript
Next.js は TypeScript を内蔵しており、新しいプロジェクトを create-next-app で作成する際に、必要なパッケージを自動的にインストールし、適切な設定を行います。
既存のプロジェクトに TypeScript を追加するには、ファイルを .ts / .tsx にリネームします。next dev および next build を実行すると、必要な依存関係が自動的にインストールされ、推奨される設定オプションを持つ tsconfig.json ファイルが追加されます。
知っておくと良いこと: 既に
jsconfig.jsonファイルがある場合は、古いjsconfig.jsonからpathsコンパイラオプションを新しいtsconfig.jsonファイルにコピーし、古いjsconfig.jsonファイルを削除してください。
IDE プラグイン
Next.js にはカスタム TypeScript プラグインと型チェッカーが含まれており、VSCode などのコードエディターで高度な型チェックやオートコンプリートに使用できます。
VS Code でプラグインを有効にするには、
- コマンドパレットを開く(
Ctrl/⌘+Shift+P) - 「TypeScript: Select TypeScript Version」を検索
- 「Use Workspace Version」を選択

これで、ファイルを編集する際にカスタムプラグインが有効になります。next build を実行すると、カスタム型チェッカーが使用されます。
TypeScript プラグインは以下のことに役立ちます。
- セグメント設定オプションに無効な値が渡された場合の警告。
- 利用可能なオプションとコンテキスト内ドキュメントの表示。
'use client'ディレクティブが正しく使用されていることを保証。- クライアントフック(
useStateなど)がクライアントコンポーネントでのみ使用されていることを保証。
🎥 ウォッチ: 内蔵 TypeScript プラグインについて学ぶ → YouTube(3分)
エンドツーエンドの型安全性
Next.js の App Router は強化された型安全性を備えています。これには以下が含まれます。
- フェッチ関数とページの間のデータのシリアライゼーションなし: サーバー上のコンポーネント、レイアウト、ページで直接
fetchを実行できます。このデータは、クライアント側で React で消費するためにシリアライズ(文字列に変換)する必要はありません。代わりに、appはデフォルトでサーバーコンポーネントを使用するため、Date、Map、Setなどを追加の手順なしに使用できます。以前は、Next.js 固有の型でサーバーとクライアントの境界を手動で型付けする必要がありました。 - コンポーネント間のデータフローの合理化:
_appをルートレイアウトに置き換えたことで、コンポーネントとページ間のデータフローを視覚化しやすくなりました。以前は、個々のpagesと_app間のデータフローは型付けが難しく、混乱を招くバグの原因となる可能性がありました。App Router での共配置されたデータフェッチにより、これはもはや問題ではありません。
Next.js でのデータフェッチは、データベースまたはコンテンツプロバイダーの選択に限定されず、可能な限りエンドツーエンドの型安全性を実現します。
期待どおりに、通常の TypeScript を使用してレスポンスデータを型付けできます。たとえば、
async function getData() {
const res = await fetch('https://api.example.com/...')
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
return res.json()
}
export default async function Page() {
const name = await getData()
return '...'
}完全なエンドツーエンドの型安全性には、データベースまたはコンテンツプロバイダーが TypeScript をサポートしていることも必要です。これは、ORM または型安全なクエリビルダーを使用することによって実現できます。
ルート認識型ヘルパー
Next.js は App Router のルート型用のグローバルヘルパーを生成します。これらはインポートなしで利用でき、next dev、next build、または next typegen 経由で生成されます。
例
Next.js 設定ファイルの型チェック
next.config.ts を使用して、Next.js 設定で TypeScript と型のインポートを使用できます。
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
/* config options here */
}
export default nextConfig現在、next.config.ts のモジュール解決は CommonJS に限定されています。ただし、Node.js v22.10.0 以降でNode.js ネイティブ TypeScript リゾルバーを使用している場合、ECMAScript Modules (ESM) 構文が利用可能です。
next.config.js ファイルを使用する場合、JSDoc を使用して IDE で型チェックを追加できます。以下に例を示します。
// @ts-check
/** @type {import('next').NextConfig} */
const nextConfig = {
/* config options here */
}
module.exports = nextConfignext.config.ts 用の Node.js ネイティブ TypeScript リゾルバーの使用
注意: Node.js v22.10.0 以降で利用可能、かつ機能が有効な場合にのみ使用できます。Next.js はこれを有効にしません。
Next.js は、Node.js ネイティブ TypeScript リゾルバー を process.features.typescript 経由で検出します。これはv22.10.0 で追加されました。存在する場合、next.config.ts はトップレベル await や動的な import() を含むネイティブ ESM を使用できます。このメカニズムは Node のリゾルバーの機能と制限を継承します。
Node.js バージョンv22.18.0+ では、process.features.typescript はデフォルトで有効になっています。v22.10.0 から 22.17.x の間のバージョンでは、NODE_OPTIONS=--experimental-transform-types でオプトインしてください。
NODE_OPTIONS=--experimental-transform-types next <command>CommonJS プロジェクトの場合(デフォルト)
next.config.ts は CommonJS プロジェクトでネイティブ ESM 構文をサポートしていますが、Node.js はデフォルトで next.config.ts を CommonJS ファイルと見なします。そのため、モジュール構文が検出されると Node.js はファイルを ESM として再解析します。したがって、CommonJS プロジェクトでは next.config.mts ファイルを使用して、それが ESM モジュールであることを明示的に示すことをお勧めします。
import type { NextConfig } from 'next'
// Top-level await and dynamic import are supported
const flags = await import('./flags.js').then((m) => m.default ?? m)
const nextConfig: NextConfig = {
/* config options here */
typedRoutes: Boolean(flags?.typedRoutes),
}
export default nextConfigESM プロジェクトの場合
package.json で "type" が "module" に設定されている場合、プロジェクトは ESM を使用します。この設定の詳細については、Node.js ドキュメント を参照してください。この場合、next.config.ts を ESM 構文で直接記述できます。
知っておくと良いこと:
package.jsonで"type": "module"を使用する場合、プロジェクト内のすべての.jsおよび.tsファイルはデフォルトで ESM モジュールとして扱われます。必要に応じて、CommonJS 構文のファイル名を.cjsまたは.cts拡張子にリネームする必要がある場合があります。
静的に型付けされたリンク
Next.js は、next/link を使用する際にタイポやその他のエラーを防ぐために、リンクを静的に型付けすることができます。これにより、ページ間のナビゲーション時の型安全性が向上します。
Pages Router と App Router の両方で、next/link の href プロパティに対して機能します。App Router では、push、replace、prefetch などの next/navigation メソッドも型付けされます。Pages Router の next/router メソッドは型付けされません。
リテラル href 文字列は検証されますが、非リテラル href の場合は as Route でキャストする必要がある場合があります。
この機能を利用するには、typedRoutes を有効にし、プロジェクトで TypeScript を使用する必要があります。
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
typedRoutes: true,
}
export default nextConfigNext.js は、アプリケーション内のすべての既存のルートに関する情報を含むリンク定義を .next/types に生成します。TypeScript は、これをエディターで無効なリンクに関するフィードバックを提供するために使用できます。
知っておくと良いこと: プロジェクトを
create-next-appなしでセットアップした場合、tsconfig.jsonのinclude配列に.next/types/**/*.tsを追加して、生成された Next.js の型が含まれるようにしてください。
{
"include": [
"next-env.d.ts",
".next/types/**/*.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": ["node_modules"]
}現在、サポートは文字列リテラル(動的セグメントを含む)にまで及んでいます。非リテラル文字列の場合は、as Route で手動でキャストする必要があります。以下の例では、next/link と next/navigation の両方の使用方法を示しています。
'use client'
import type { Route } from 'next'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
export default function Example() {
const router = useRouter()
const slug = 'nextjs'
return (
<>
{/* Link: literal and dynamic */}
<Link href="/about" />
<Link href={`/blog/${slug}`} />
<Link href={('/blog/' + slug) as Route} />
{/* TypeScript error if href is not a valid route */}
<Link href="/aboot" />
{/* Router: literal and dynamic strings are validated */}
<button onClick={() => router.push('/about')}>Push About</button>
<button onClick={() => router.replace(`/blog/${slug}`)}>
Replace Blog
</button>
<button onClick={() => router.prefetch('/contact')}>
Prefetch Contact
</button>
{/* For non-literal strings, cast to Route */}
<button onClick={() => router.push(('/blog/' + slug) as Route)}>
Push Non-literal Blog
</button>
</>
)
}プロキシによって定義されたリダイレクトルートについても同様です。
import { NextRequest, NextResponse } from 'next/server'
export function proxy(request: NextRequest) {
if (request.nextUrl.pathname === '/proxy-redirect') {
return NextResponse.redirect(new URL('/', request.url))
}
return NextResponse.next()
}import type { Route } from 'next'
export default function Page() {
return <Link href={'/proxy-redirect' as Route}>Link Text</Link>
}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>My Card</div>
</Link>
)
}単純なデータ構造を型付けして、リンクをレンダリングするために反復処理することもできます。
import type { Route } from 'next'
type NavItem<T extends string = string> = {
href: T
label: string
}
export const navItems: NavItem<Route>[] = [
{ href: '/', label: 'Home' },
{ href: '/about', label: 'About' },
{ href: '/blog', label: 'Blog' },
]次に、アイテムをマッピングして Link をレンダリングします。
import Link from 'next/link'
import { navItems } from './nav-items'
export function Nav() {
return (
<nav>
{navItems.map((item) => (
<Link key={item.href} href={item.href}>
{item.label}
</Link>
))}
</nav>
)
}どのように機能しますか?
next devまたはnext buildを実行すると、Next.js は.next内に非表示の.d.tsファイルを生成します。このファイルには、アプリケーション内のすべての既存のルート(Linkのhref型としてのすべての有効なルート)に関する情報が含まれています。この.d.tsファイルはtsconfig.jsonに含まれており、TypeScript コンパイラは.d.tsをチェックし、エディターで無効なリンクに関するフィードバックを提供します。
環境変数用の型イントロスペクション
開発中、Next.js は .next/types に .d.ts ファイルを生成します。このファイルには、エディターのイントロスペクションのためにロードされた環境変数に関する情報が含まれています。同じ環境変数キーが複数のファイルに定義されている場合、環境変数ロード順に従って重複排除されます。
この機能を利用するには、experimental.typedEnv を有効にし、プロジェクトで TypeScript を使用する必要があります。
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
typedEnv: true,
},
}
export default nextConfig知っておくと良いこと: 型は、開発実行時にロードされた環境変数に基づいて生成されます。これには、デフォルトで
.env.production*ファイルからの変数が除外されます。本番環境固有の変数をインクルードするには、NODE_ENV=productionでnext devを実行します。
非同期サーバーコンポーネント付き
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 で有効にした場合にサポートしており、これにより大規模なアプリケーションの型チェックを高速化できます。
カスタム tsconfig パス
場合によっては、ビルドまたはツールのために異なる TypeScript 設定を使用したい場合があります。そのために、next.config.ts で typescript.tsconfigPath を設定して、Next.js を別の tsconfig ファイルにポイントさせます。
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
typescript: {
tsconfigPath: 'tsconfig.build.json',
},
}
export default nextConfigたとえば、本番ビルドのために別の設定に切り替えます。
import type { NextConfig } from 'next'
const isProd = process.env.NODE_ENV === 'production'
const nextConfig: NextConfig = {
typescript: {
tsconfigPath: isProd ? 'tsconfig.build.json' : 'tsconfig.json',
},
}
export default nextConfig別の tsconfig をビルドに使用する理由
モノレポなどのシナリオでは、ビルドがプロジェクトの標準に一致しない共有依存関係も検証するため、チェックを緩和する必要がある場合があります。または、CI でチェックを緩めて、ローカルでのより厳格な TypeScript 設定への移行を継続しつつ(それでも IDE で誤用をハイライトさせたい場合)も、ビルドを続行したい場合などです。
たとえば、プロジェクトが useUnknownInCatchVariables を使用しているが、一部のモノレポ依存関係がまだ any を想定している場合。
{
"extends": "./tsconfig.json",
"compilerOptions": {
"useUnknownInCatchVariables": false
}
}これにより、IDE は tsconfig.json を通じて厳格に保たれ、本番ビルドは代替設定を使用できます。
知っておくと良いこと:
- 通常、IDE は診断とイントロスペクションのために
tsconfig.jsonを読み取ります。そのため、本番ビルドが代替設定を使用している間でも、IDE の警告を確認できます。エディターでの整合性を確保するには、重要なオプションをミラーリングしてください。- 開発中、
tsconfig.jsonのみが変更を監視されます。typescript.tsconfigPathを介して別のファイル名を編集した場合、設定を適用するには開発サーバーを再起動してください。- 設定されたファイルは、
next dev、next build、およびnext typegenで使用されます。
本番環境での TypeScript エラーの無効化
Next.js は、プロジェクトに TypeScript エラーが存在する場合、本番ビルド(next build)を失敗させます。
アプリケーションにエラーがあっても Next.js に本番コードを(危険を冒して)生成させたい場合は、組み込みの型チェックステップを無効にすることができます。
無効にした場合、ビルドプロセスの一部として型チェックを実行していることを確認してください。そうでなければ、非常に危険になる可能性があります。
next.config.ts を開き、typescript 設定で ignoreBuildErrors オプションを有効にします。
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
typescript: {
// !! WARN !!
// Dangerously allow production builds to successfully complete even if
// your project has type errors.
// !! WARN !!
ignoreBuildErrors: true,
},
}
export default nextConfig知っておくと良いこと: ビルド前に
tsc --noEmitを実行して TypeScript エラーを自分でチェックできます。これは CI/CD パイプラインで、デプロイ前に TypeScript エラーをチェックしたい場合に役立ちます。
カスタム型宣言
カスタム型を宣言する必要がある場合、next-env.d.ts を変更したくなるかもしれませんが、このファイルは自動生成されるため、変更は上書きされてしまいます。代わりに、new-types.d.ts のような新しいファイルを作成し、tsconfig.json で参照してください。
{
"compilerOptions": {
"skipLibCheck": true
//...truncated...
},
"include": [
"new-types.d.ts",
"next-env.d.ts",
".next/types/**/*.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": ["node_modules"]
}バージョン変更履歴
| バージョン | 変更履歴 |
|---|---|
v15.0.0 | next.config.ts で TypeScript プロジェクトのサポートが追加されました。 |
v13.2.0 | 静的に型付けされたリンクがベータ版で利用可能になりました。 |
v12.0.0 | TypeScript および TSX のコンパイルには、デフォルトで SWC が使用され、ビルドが高速化されます。 |
v10.2.1 | tsconfig.json で有効にした場合の インクリメンタル型チェック のサポートが追加されました。 |
役に立ちましたか?
