mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
1238 字
6 分钟
导 出 导 入 一 定 要 会

背景#

在学习 nextjs 的时候,经常会遇到导出类型和类型擦除的相关问题

基础内容-导出与导入#

可以这么理解,每一个 .ts 的文件都是一个代码库,如果不 export 的话他就是私有的,外部不能使用。

导出(export)#

  1. 具名导出(Named export):一个文件可以有多个带有名字的导出
export const age = 20;
export function L1ngg() { ... }
  1. 默认导出(Default export):一个文件只能有一个默认导出
export default function defaultL1ngg() { ... }

导入(import)#

  1. 对于 Named export ,必须使用 {} 且名字要对应:import { age , L1ngg } from xxx
  2. 对于 Default export ,可以随便取名:import randomName from xxx

TS特色之值与类型的混合传递#

这是ts语法特殊的地方,可以同时导出具体的变量(运行时候的值)和接口(编译时候的类型)。

math.ts
export const PI = 3.14;
export interface CircleConfig {
radius: number;
}

当导入的时候就可以混合在一起导入 import { PI, CircleConfig } from './math'

关于 import type#

TS 编译为 JS 的时候,所有的类型将会消失。如果仅仅是为了获取类型信息(比如给某个变量标记为interface),并不需要运行时的代码,TS 建议使用 import type

示例:

//TS 源码
import type { UserInterface } from "./types";
import { userService } from "./services";
const user: UserInterface = userService.get();

编译后的 JS

// UserInterface 的导入直接消失了,因为它只是个类型
import { userService } from './services';
var user = userService.get();

💡 深入了解类型擦除:想要深入理解类型擦除的工作原理、哪些内容会被擦除、哪些会保留,以及如何正确处理运行时类型检查?请阅读:TypeScript 类型擦除深入理解

为什么要使用 import type#

使用 import type 有以下几个重要好处:

  1. 打包优化:避免将仅用于类型标注的模块打包进最终代码,减小打包体积
  2. 明确意图:让其他开发者一眼看出这是纯类型导入,提高代码可读性
  3. 避免副作用:某些模块在导入时会执行代码(如注册全局变量),使用 import type 可以避免这些副作用
  4. 解决循环依赖:在某些循环依赖场景下,import type 可以打破循环引用

export type 的使用#

import type 对应,导出也可以使用 export type 来明确只导出类型:

// types.ts - 只导出类型
export type { UserInterface, AdminInterface } from "./interfaces";
// services.ts - 混合导出类型和值
export { userService } from "./user-service";
export type { UserInterface } from "./interfaces";

内联类型导入(TS 3.8+)#

TypeScript 3.8 引入了更灵活的语法,可以在同一个 import 语句中混合导入类型和值:

// 新语法:在花括号内使用 type 关键字标记类型
import { userService, type UserInterface, type AdminInterface } from "./module";
// 等价于分开写(旧语法)
import type { UserInterface, AdminInterface } from "./module";
import { userService } from "./module";

这种写法的优点是代码更简洁优雅,特别是当需要从同一个模块导入多个类型和值时。

常见错误#

CAUTION

使用 import type 时需要注意以下几点:

1. 不能对 import type 导入的内容做运行时操作

import type { User } from "./types";
// ❌ 错误:User 在运行时不存在,无法实例化
const user = new User();
// ✅ 正确:只用于类型标注
const user: User = { name: "L1ngg", age: 20 };

2. 类(Class)既是类型也是值

user.ts
export class User {
constructor(public name: string) {}
}
// 如果使用 import type 导入类
import type { User } from "./user";
const user: User = { name: "L1ngg" }; // ✅ 可以用作类型
const user2 = new User("L1ngg"); // ❌ 错误:运行时不存在
// 如果需要实例化,必须使用普通 import
import { User } from "./user";
const user = new User("L1ngg"); // ✅ 正确

在 Next.js 中的应用#

在 Next.js 项目中,正确使用 import type 尤为重要,特别是在处理服务端组件和客户端组件的边界时。

1. 服务端和客户端组件的类型共享

// types/user.ts - 共享类型定义
export interface UserProfile {
id: string;
name: string;
email: string;
}
// app/components/UserCard.tsx - 客户端组件
"use client";
import type { UserProfile } from "@/types/user"; // 只导入类型
export function UserCard({ user }: { user: UserProfile }) {
return <div>{user.name}</div>;
}

2. Server Actions 中的类型传递

// app/actions/user.ts - Server Action
"use server";
import type { UserProfile } from "@/types/user";
export async function updateUser(data: UserProfile) {
// 服务端逻辑
return { success: true };
}
// app/components/UserForm.tsx - 客户端组件
("use client");
import { updateUser } from "@/app/actions/user";
import type { UserProfile } from "@/types/user";
export function UserForm() {
const handleSubmit = async (data: UserProfile) => {
await updateUser(data);
};
// ...
}

3. TypeScript 配置建议

在 Next.js 项目中,建议在 tsconfig.json 中开启以下配置:

{
"compilerOptions": {
"isolatedModules": true, // Next.js 推荐开启,确保每个文件都能独立编译
"verbatimModuleSyntax": true // TS 5.0+ 新选项,更严格地检查导入导出
}
}

这些配置可以帮助你更早地发现类型导入的问题,避免运行时错误。

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

导 出 导 入 一 定 要 会
https://l1ngg.info/posts/tech/ts-import-export/
作者
L1ngg
发布于
2026-02-02
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00