Next.js 内置了 TypeScript 支持,当您使用 create-next-app 创建新项目时,它会自动安装必要的包并配置适当的设置。
要将 TypeScript 添加到现有项目,请将文件重命名为 .ts / .tsx。运行 next dev 和 next build,即可自动安装必要的依赖项,并添加一个包含推荐配置选项的 tsconfig.json 文件。
须知:如果您已有
jsconfig.json文件,请将旧jsconfig.json文件中的paths编译器选项复制到新的tsconfig.json文件中,并删除旧的jsconfig.json文件。
Next.js 包含一个自定义的 TypeScript 插件和类型检查器,VSCode 和其他代码编辑器可以使用它进行高级类型检查和自动补全。
您可以通过以下步骤在 VS Code 中启用该插件:
Ctrl/⌘ + Shift + P)

现在,当编辑文件时,自定义插件将被启用。运行 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.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 模块 (ESM) 语法可用。
当使用 next.config.js 文件时,您可以使用 JSDoc 在 IDE 中添加一些类型检查,如下所示:
// @ts-check
/** @type {import('next').NextConfig} */
const nextConfig = {
/* config options here */
};
module.exports = nextConfig;next.config.ts 使用 Node.js 原生 TypeScript 解析器注意:适用于 Node.js v22.10.0+,且仅当该功能启用时。Next.js 不会默认启用它。
Next.js 通过 process.features.typescript 检测 Node.js 原生 TypeScript 解析器,该解析器在 v22.10.0 中添加。当存在时,next.config.ts 可以使用原生 ESM,包括顶层 await 和动态 import()。这种机制继承了 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>尽管 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 nextConfig;当 package.json 中 "type" 设置为 "module" 时,您的项目使用 ESM。您可以在 Node.js 文档 中了解有关此设置的更多信息。在这种情况下,您可以直接使用 ESM 语法编写 next.config.ts。
须知:当在
package.json中使用"type": "module"时,项目中所有.js和.ts文件默认都会被视为 ESM 模块。如果需要,您可能需要将使用 CommonJS 语法的文件重命名为.cjs或.cts扩展名。
Next.js 可以对链接进行静态类型检查,以在使用 next/link 时防止拼写错误和其他错误,从而提高页面导航时的类型安全性。
它在 Pages Router 和 App Router 中都适用于 next/link 中的 href 属性。在 App Router 中,它还为 next/navigation 的方法(如 push、replace 和 prefetch)提供类型。它不为 Pages Router 中的 next/router 方法提供类型。
字面量 href 字符串会进行验证,而非字面量 href 可能需要使用 as Route 进行类型转换。
要启用此功能,需要启用 typedRoutes 并且项目需要使用 TypeScript。
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
typedRoutes: true,
};
export default nextConfig;Next.js 将在 .next/types 中生成一个链接定义,其中包含有关应用程序中所有现有路由的信息,然后 TypeScript 可以使用这些信息在您的编辑器中提供有关无效链接的反馈。
须知:如果您在没有使用
create-next-app的情况下设置项目,请通过将.next/types/**/*.ts添加到tsconfig.json的include数组中,确保包含生成的 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>
</>
)
}
```对于通过代理定义的路由重定向,也适用同样的方法:
```ts filename="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()
}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。
要将 async 服务器组件与 TypeScript 结合使用,请确保您使用的是 TypeScript 5.1.3 或更高版本以及 @types/react 18.2.8 或更高版本。
如果您使用的是旧版 TypeScript,可能会看到 'Promise<Element>' is not a valid JSX element 类型错误。更新到最新版本的 TypeScript 和 @types/react 应该可以解决此问题。
对于 getStaticProps、getStaticPaths 和 getServerSideProps,您可以分别使用 GetStaticProps、GetStaticPaths 和 GetServerSideProps 类型:
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;须知:
satisfies是在 TypeScript 4.9 中添加的。我们建议升级到最新版本的 TypeScript。
以下是如何为 API 路由使用内置类型的一个示例:
import type { NextApiRequest, NextApiResponse } from "next";
export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json({ name: "John Doe" });
}您还可以为响应数据定义类型:
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 使用如果您有 自定义 App,可以使用内置类型 AppProps 并将文件名更改为 ./pages/_app.tsx,如下所示:
import type { AppProps } from "next/app";
export default function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
}自 v10.2.1 起,当在 tsconfig.json 中启用时,Next.js 支持 增量类型检查,这有助于加快大型应用程序中的类型检查速度。
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在某些情况下,您可能需要放宽检查,例如在 monorepos 中,构建也会验证不符合您项目标准的共享依赖项,或者在 CI 中放宽检查以在本地迁移到更严格的 TypeScript 设置时继续交付(并且仍然希望您的 IDE 突出显示错误使用)。
例如,如果您的项目使用 useUnknownInCatchVariables 但某些 monorepo 依赖项仍假定为 any:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"useUnknownInCatchVariables": false
}
}这使得您的编辑器通过 tsconfig.json 保持严格,同时允许生产构建使用宽松的设置。
须知:
- IDE 通常会读取
tsconfig.json进行诊断和智能提示,因此在生产构建使用备用配置时,您仍然可以看到 IDE 警告。如果您希望编辑器中保持一致,请镜像关键选项。- 在开发中,只有
tsconfig.json会被监听更改。如果您通过typescript.tsconfigPath编辑了不同的文件名,请重启开发服务器以应用更改。- 配置的文件用于
next dev、next build和next typegen。
当您的项目中存在 TypeScript 错误时,Next.js 会使您的 生产构建 (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 | SWC 现在默认用于编译 TypeScript 和 TSX,以实现更快的构建。 |
| v10.2.1 | 增量类型检查 支持已添加,当在您的 tsconfig.json 中启用时。 |