Skip to content

TypeScript

Next.js 带有内置 TypeScript,当你使用 create-next-app 创建新项目时,它会自动安装必要的软件包并配置适当的设置。

¥Next.js comes with built-in TypeScript, automatically installing the necessary packages and configuring the proper settings when you create a new project with create-next-app.

要将 TypeScript 添加到现有项目,请将文件重命名为 .ts / .tsx。运行 next devnext build 自动安装必要的依赖,并添加具有推荐配置选项的 tsconfig.json 文件。

¥To add TypeScript to an existing project, rename a file to .ts / .tsx. Run next dev and next build to automatically install the necessary dependencies and add a tsconfig.json file with the recommended config options.

需要了解:如果你已经有 jsconfig.json 文件,请将 paths 编译器选项从旧的 jsconfig.json 复制到新的 tsconfig.json 文件中,然后删除旧的 jsconfig.json 文件。

¥Good to know: If you already have a jsconfig.json file, copy the paths compiler option from the old jsconfig.json into the new tsconfig.json file, and delete the old jsconfig.json file.

next-env.d.ts

Next.js 会在项目根目录生成一个 next-env.d.ts 文件。此文件引用 Next.js 类型定义,使 TypeScript 能够识别非代码导入(例如图片、样式表等)和 Next.js 特有的类型。

¥Next.js generates a next-env.d.ts file in your project root. This file references Next.js type definitions, allowing TypeScript to recognize non-code imports (images, stylesheets, etc.) and Next.js-specific types.

运行 next devnext buildnext typegen 会重新生成此文件。

¥Running next dev, next build, or next typegen regenerates this file.

需要了解:

¥Good to know:

  • 我们建议将 next-env.d.ts 添加到你的 .gitignore 文件中。

    ¥We recommend adding next-env.d.ts to your .gitignore file.

  • 该文件必须位于你的 tsconfig.json include 数组中(create-next-app 会自动执行此操作)。

    ¥The file must be in your tsconfig.json include array (create-next-app does this automatically).

示例

¥Examples

Next.js 配置文件类型检查

¥Type Checking Next.js Configuration Files

你可以使用 TypeScript 并在 Next.js 配置中使用 next.config.ts 导入类型。

¥You can use TypeScript and import types in your Next.js configuration by using next.config.ts.

ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  /* config options here */
}

export default nextConfig

next.config.ts 中的模块解析目前仅限于 CommonJS。但是,当 使用 Node.js 原生 TypeScript 解析器 适用于 Node.js v22.10.0 及更高版本时,可以使用 ECMAScript 模块 (ESM) 语法。

¥Module resolution in next.config.ts is currently limited to CommonJS. However, ECMAScript Modules (ESM) syntax is available when using Node.js native TypeScript resolver for Node.js v22.10.0 and higher.

使用 next.config.js 文件时,你可以使用 JSDoc 在 IDE 中添加一些类型检查,如下所示:

¥When using the next.config.js file, you can add some type checking in your IDE using JSDoc as below:

使用 Node.js Native TypeScript Resolver for next.config.ts

¥Using Node.js Native TypeScript Resolver for next.config.ts

注意:适用于 Node.js v22.10.0 及更高版本,且仅在启用该功能时可用。Next.js 不会启用 。

¥Note: Available on Node.js v22.10.0+ and only when the feature is enabled. Next.js does not enable it.

Next.js 通过 v22.10.0 版本新增的 process.features.typescript 来检测 Node.js 原生 TypeScript 解析器。如果存在,next.config.ts 可以使用原生 ESM,包括顶层 await 和动态 import()。此机制继承了 Node 解析器的功能和限制。

¥Next.js detects the Node.js native TypeScript resolver via process.features.typescript, added in v22.10.0. When present, next.config.ts can use native ESM, including top‑level await and dynamic import(). This mechanism inherits the capabilities and limitations of Node's resolver.

在 Node.js 版本 v22.18.0 及更高版本中,process.features.typescript 默认启用。对于 v22.10.0 到 22.17.x 之间的版本,请使用 NODE_OPTIONS=--experimental-transform-types 启用:

¥In Node.js versions v22.18.0+, process.features.typescript is enabled by default. For versions between v22.10.0 and 22.17.x, opt in with NODE_OPTIONS=--experimental-transform-types:

bash
NODE_OPTIONS=--experimental-transform-types next <command>

适用于 CommonJS 项目(默认)

¥For CommonJS Projects (Default)

尽管 next.config.ts 支持 CommonJS 项目中的原生 ESM 语法,但 Node.js 默认仍会将 next.config.ts 视为 CommonJS 文件,因此当检测到模块语法时,Node.js 会将该文件重新解析为 ESM。因此,我们建议 CommonJS 项目使用 next.config.mts 文件来明确指示它是一个 ESM 模块:

¥Although next.config.ts supports native ESM syntax in CommonJS projects, Node.js will still assume next.config.ts is a CommonJS file by default, resulting in Node.js reparsing the file as ESM when module syntax is detected. Therefore, we recommend using the next.config.mts file for CommonJS projects to explicitly indicate it's an ESM module:

ts
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 nextConfig

适用于 ESM 项目

¥For ESM Projects

package.json 中的 "type" 设置为 "module" 时,你的项目将使用 ESM。了解更多关于此设置 在 Node.js 文档中 的信息。在这种情况下,你可以使用 ESM 语法直接编写 next.config.ts

¥When "type" is set to "module" in package.json, your project uses ESM. Learn more about this setting in the Node.js docs. In this case, you can write next.config.ts directly with ESM syntax.

需要了解:在 package.json 中使用 "type": "module" 时,项目中所有 .js.ts 文件默认都被视为 ESM 模块。如果需要,你可能需要将使用 CommonJS 语法的文件重命名为 .cjs.cts 扩展名。

¥Good to know: When using "type": "module" in your package.json, all .js and .ts files in your project are treated as ESM modules by default. You may need to rename files with CommonJS syntax to .cjs or .cts extensions if needed.

¥Statically Typed Links

Next.js 可以静态键入链接,以防止使用 next/link 时的拼写错误和其他错误,从而提高在页面之间导航时的类型安全性。

¥Next.js can statically type links to prevent typos and other errors when using next/link, improving type safety when navigating between pages.

在页面和应用路由中,next/link 中的 href 属性均可用。在 App Router 中,它还会将 next/navigation 方法(例如 pushreplaceprefetch)进行类型化。它不会对页面路由中的 next/router 方法进行类型检查。

¥Works in both the Pages and App Router for the href prop in next/link. In the App Router, it also types next/navigation methods like push, replace, and prefetch. It does not type next/router methods in Pages Router.

字面量字符串 href 会被验证,而非字面量字符串 href 可能需要使用 as Route 进行类型转换。

¥Literal href strings are validated, while non-literal hrefs may require a cast with as Route.

要选择启用此功能,需要启用 typedRoutes 并且项目需要使用 TypeScript。

¥To opt-into this feature, typedRoutes needs to be enabled and the project needs to be using TypeScript.

ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  typedRoutes: true,
}

export default nextConfig

Next.js 将在 .next/types 中生成一个链接定义,其中包含有关应用中所有现有路由的信息,然后 TypeScript 可以使用该信息在编辑器中提供有关无效链接的反馈。

¥Next.js will generate a link definition in .next/types that contains information about all existing routes in your application, which TypeScript can then use to provide feedback in your editor about invalid links.

需要了解:如果你在设置项目时未使用 create-next-app,请确保生成的 Next.js 类型包含在内,方法是在 tsconfig.jsoninclude 数组中添加 .next/types/**/*.ts

¥Good to know: If you set up your project without create-next-app, ensure the generated Next.js types are included by adding .next/types/**/*.ts to the include array in your tsconfig.json:

目前,支持任何字符串字面量,包括动态段。对于非字面字符串,你需要使用 as Route 手动进行类型转换。以下示例展示了 next/linknext/navigation 的用法:

¥Currently, support includes any string literal, including dynamic segments. For non-literal strings, you need to manually cast with as Route. The example below shows both next/link and next/navigation usage:

tsx
'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>
    </>
  )
}

这同样适用于通过代理定义的重定向路由:

¥The same applies for redirecting routes defined by proxy:

ts
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()
}
tsx
import type { Route } from 'next'

export default function Page() {
  return <Link href={'/proxy-redirect' as Route}>Link Text</Link>
}

要在封装 next/link 的自定义组件中接受 href,请使用泛型:

¥To accept href in a custom component wrapping next/link, use a generic:

tsx
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>
  )
}

你还可以输入一个简单的数据结构并迭代以渲染链接:

¥You can also type a simple data structure and iterate to render links:

ts
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

¥Then, map over the items to render Links:

tsx
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>
  )
}

它是如何工作的?

¥How does it work?

运行 next devnext build 时,Next.js 会在 .next 内生成一个隐藏的 .d.ts 文件,其中包含有关应用中所有现有路由的信息(所有有效路由为 Linkhref 类型)。此 .d.ts 文件包含在 tsconfig.json 中,TypeScript 编译器将检查 .d.ts 并在编辑器中提供有关无效链接的反馈。

¥When running next dev or next build, Next.js generates a hidden .d.ts file inside .next that contains information about all existing routes in your application (all valid routes as the href type of Link). This .d.ts file is included in tsconfig.json and the TypeScript compiler will check that .d.ts and provide feedback in your editor about invalid links.

环境变量的类型智能感知

¥Type IntelliSense for Environment Variables

在开发过程中,Next.js 会在 .next/types 中生成一个 .d.ts 文件,其中包含编辑器 IntelliSense 已加载环境变量的信息。如果在多个文件中定义了相同的环境变量键,则会根据 环境变量加载顺序 对其进行数据去重。

¥During development, Next.js generates a .d.ts file in .next/types that contains information about the loaded environment variables for your editor's IntelliSense. If the same environment variable key is defined in multiple files, it is deduplicated according to the Environment Variable Load Order.

要选择启用此功能,需要启用 experimental.typedEnv 并且项目需要使用 TypeScript。

¥To opt-into this feature, experimental.typedEnv needs to be enabled and the project needs to be using TypeScript.

ts
import type { NextConfig } from 'next'

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

export default nextConfig

需要了解:类型是根据开发运行时加载的环境变量生成的,默认情况下会排除 .env.production* 文件中的变量。要包含特定于生产的变量,请将 next devNODE_ENV=production 一起运行。

¥Good to know: Types are generated based on the environment variables loaded at development runtime, which excludes variables from .env.production* files by default. To include production-specific variables, run next dev with NODE_ENV=production.

静态生成和服务端渲染

¥Static Generation and Server-side Rendering

对于 getStaticPropsgetStaticPathsgetServerSideProps,你可以分别使用 GetStaticPropsGetStaticPathsGetServerSideProps 类型:

¥For getStaticProps, getStaticPaths, and getServerSideProps, you can use the GetStaticProps, GetStaticPaths, and GetServerSideProps types respectively:

tsx
import type { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next'

export const getStaticProps = (async (context) => {
  // ...
}) satisfies GetStaticProps

export const getStaticPaths = (async () => {
  // ...
}) satisfies GetStaticPaths

export const getServerSideProps = (async (context) => {
  // ...
}) satisfies GetServerSideProps

需要了解:satisfies4.9 中已添加到 TypeScript 中。我们建议升级到最新版本的 TypeScript。

¥Good to know: satisfies was added to TypeScript in 4.9. We recommend upgrading to the latest version of TypeScript.

使用 API 路由

¥With API Routes

以下是如何将内置类型用于 API 路由的示例:

¥The following is an example of how to use the built-in types for API routes:

ts
import type { NextApiRequest, NextApiResponse } from 'next'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  res.status(200).json({ name: 'John Doe' })
}

你还可以输入响应数据:

¥You can also type the response data:

ts
import type { NextApiRequest, NextApiResponse } from 'next'

type Data = {
  name: string
}

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {
  res.status(200).json({ name: 'John Doe' })
}

使用自定义 App

¥With custom App

如果你有 定制 App,则可以使用内置类型 AppProps 并将文件名更改为 ./pages/_app.tsx,如下所示:

¥If you have a custom App, you can use the built-in type AppProps and change file name to ./pages/_app.tsx like so:

ts
import type { AppProps } from 'next/app'

export default function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

增量类型检查

¥Incremental type checking

由于 v10.2.1 Next.js 在 tsconfig.json 中启用时支持 增量类型检查,因此这可以帮助加快大型应用中的类型检查速度。

¥Since v10.2.1 Next.js supports incremental type checking when enabled in your tsconfig.json, this can help speed up type checking in larger applications.

自定义 tsconfig 路径

¥Custom tsconfig path

在某些情况下,你可能需要为构建或工具使用不同的 TypeScript 配置。为此,请在 next.config.ts 中设置 typescript.tsconfigPath,使 Next.js 指向另一个 tsconfig 文件。

¥In some cases, you might want to use a different TypeScript configuration for builds or tooling. To do that, set typescript.tsconfigPath in next.config.ts to point Next.js to another tsconfig file.

ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  typescript: {
    tsconfigPath: 'tsconfig.build.json',
  },
}

export default nextConfig

例如,切换到不同的配置以用于生产环境构建:

¥For example, switch to a different config for production builds:

ts
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
Why you might use a separate `tsconfig` for builds

在类似 monorepos 的场景中,你可能需要放宽检查。在 monorepos 中,构建过程还会验证不符合项目标准的共享依赖。或者,在 CI 中放宽检查以在本地迁移到更严格的 TypeScript 设置的同时继续交付(并且仍然希望 IDE 高亮误用),也可能需要放宽检查。

¥You might need to relax checks in scenarios like monorepos, where the build also validates shared dependencies that don't match your project's standards, or when loosening checks in CI to continue delivering while migrating locally to stricter TypeScript settings (and still wanting your IDE to highlight misuse).

例如,如果你的项目使用 useUnknownInCatchVariables,但某些 monorepo 依赖仍然假定使用 any

¥For example, if your project uses useUnknownInCatchVariables but some monorepo dependencies still assume any:

此功能通过 tsconfig.json 保持编辑器的严格性,同时允许生产版本使用宽松的设置。

¥This keeps your editor strict via tsconfig.json while allowing the production build to use relaxed settings.

需要了解:

¥Good to know:

  • IDE 通常会读取 tsconfig.json 来进行诊断和 IntelliSense 操作,因此即使生产版本使用备用配置,你仍然会看到 IDE 警告。如果你希望编辑器中的版本保持一致,请镜像关键选项。

    ¥IDEs typically read tsconfig.json for diagnostics and IntelliSense, so you can still see IDE warnings while production builds use the alternate config. Mirror critical options if you want parity in the editor.

  • 在开发环境中,仅监视 tsconfig.json 的变化。如果你通过 typescript.tsconfigPath 编辑了不同的文件名,请重启开发服务器以应用更改。

    ¥In development, only tsconfig.json is watched for changes. If you edit a different file name via typescript.tsconfigPath, restart the dev server to apply changes.

  • 配置文件在 next devnext buildnext typegen 中使用。

    ¥The configured file is used in next dev, next build, and next typegen.

在生产中禁用 TypeScript 错误

¥Disabling TypeScript errors in production

当项目中存在 TypeScript 错误时,Next.js 会导致生产构建失败 (next build)。

¥Next.js fails your production build (next build) when TypeScript errors are present in your project.

如果你希望 Next.js 即使你的应用有错误也能危险地生成生产代码,你可以禁用内置类型检查步骤。

¥If you'd like Next.js to dangerously produce production code even when your application has errors, you can disable the built-in type checking step.

如果禁用,请确保在构建或部署过程中运行类型检查,否则这可能非常危险。

¥If disabled, be sure you are running type checks as part of your build or deploy process, otherwise this can be very dangerous.

打开 next.config.ts 并在 typescript 配置中启用 ignoreBuildErrors 选项:

¥Open next.config.ts and enable the ignoreBuildErrors option in the typescript config:

ts
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 错误。这对于你希望在部署之前检查 TypeScript 错误的 CI/CD 管道很有用。

¥Good to know: You can run tsc --noEmit to check for TypeScript errors yourself before building. This is useful for CI/CD pipelines where you'd like to check for TypeScript errors before deploying.

自定义类型声明

¥Custom type declarations

当你需要声明自定义类型时,你可能会想修改 next-env.d.ts。但是,该文件是自动生成的,因此你所做的任何更改都将被覆盖。相反,你应该创建一个新文件,我们将其命名为 new-types.d.ts,并在 tsconfig.json 中引用它:

¥When you need to declare custom types, you might be tempted to modify next-env.d.ts. However, this file is automatically generated, so any changes you make will be overwritten. Instead, you should create a new file, let's call it new-types.d.ts, and reference it in your tsconfig.json:

版本变更

¥Version Changes

版本更改
v15.0.0为 TypeScript 项目添加了 next.config.ts 支持。
v13.2.0静态类型链接在测试版中可用。
v12.0.0现在默认使用 SWC 来编译 TypeScript 和 TSX 以加快构建速度。
v10.2.1tsconfig.json 中启用时添加 增量类型检查 支持。