使用 types / typings 实现全局 TypeScript 类型定义,无需 import/export

在 Vue 3 + Vite + TypeScript 项目中,我们经常需要在多个文件中使用相同的类型定义。通常的做法是:

typescript 复制代码
// user.ts
export interface User {
  id: number;
  name: string;
}

然后在其他文件中使用时导入:

python 复制代码
import type { User } from '@/types/user';

这没有问题,但在一个大型项目中,频繁 import/export 类型会显得繁琐、重复。而 TypeScript 实际上支持「全局类型声明」,允许你在项目中任何地方使用类型而不需要显式导入。

下面分析如何使用 types 或 typings 文件夹,在 Vue 3 + Vite + TypeScript 项目中配置全局类型定义。


1. 创建全局类型定义目录

你可以在项目根目录下创建一个 types 或 typings 文件夹:

lua 复制代码
your-project/
├─ src/
├─ types/          <-- 这里放全局类型定义
│  ├─ global.d.ts  <-- 推荐用 .d.ts 扩展名
│  ├─ user.d.ts
│  └─ api.d.ts
├─ vite.config.ts
├─ tsconfig.json

示例:types/user.d.ts

typescript 复制代码
// types/user.d.ts

interface User {
  id: number;
  name: string;
  email?: string;
}

⚠️ 注意:不要使用 export 或 import ,TypeScript 会自动将这类 .d.ts 文件中的类型提升为全局。


2. 配置 tsconfig.json

为了让 TypeScript 自动识别 types 目录中的类型定义,你需要在 tsconfig.json 中添加 typeRoots 或直接包含它:

perl 复制代码
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
    "typeRoots": ["./types", "./node_modules/@types"]
  },
  "include": ["src", "types"]
}

解释:

  • typeRoots: 告诉 TypeScript 在 types 目录下查找类型定义。
  • include: 包含 types 文件夹,确保类型文件被编译器扫描。

注意: typeRoots如果没有配置,会隐式的指定"./node_modules/@types",但这里我们显式的指定了,就必须显式的指定一次"./node_modules/@types"


3. 全局使用类型定义

完成以上配置后,你可以在任意 TS/JS/Vue 文件中直接使用类型:

css 复制代码
const user: User = {
  id: 1,
  name: 'Alice'
};

不需要再 import { User } from '@/types/user' 了。


与第三方类型文件区别

你可能注意到 node_modules/@types 中也有很多 .d.ts 文件(比如 @types/lodash)。这是 TypeScript 默认的全局类型路径之一。

通过上面的配置,我们也把 types/ 当作了一个"自定义的全局类型包",原理是一样的。


命名建议

建议将全局类型文件命名为:

  • global.d.ts:统一存放项目中杂项的全局类型定义
  • xxx.d.ts:按功能模块拆分,如 user.d.ts、api.d.ts、env.d.ts

⚠注意事项

项 注意
不要使用 export/import 否则类型就不再是全局,会失效
文件名需以 .d.ts 结尾 .ts 默认不当作类型声明文件处理
编辑器需重启 修改 tsconfig.json 后,需重启 VSCode或重启ts服务 才生效
不适合共享 npm 包 如果你想封装为库分发,请用 export 模块化方式

使用 declare module 声明模块类型

有时候,我们会使用一些 非 TypeScript 编写的模块 或自定义的虚拟模块(如 Vite 插件注入的模块),这些模块没有类型定义。如果我们还想在不引入第三方 .d.ts 的前提下为它们添加类型,可以用 declare module 来手动声明。


为自定义模块添加类型

假设你在 Vite 中使用了一个虚拟模块:virtual:config,但这个模块没有类型提示。

你可以在 types/modules.d.ts 中添加如下内容:

typescript 复制代码
// types/modules.d.ts

declare module 'virtual:config' {
  interface AppConfig {
    baseUrl: string;
    enableMock: boolean;
  }

  const config: AppConfig;
  export default config;
}

这样你就可以在项目中直接这样使用:

arduino 复制代码
import config from 'virtual:config';

console.log(config.baseUrl);

增强已有模块的类型(模块补充)

有时我们需要为已有模块(如 axios)增强类型,比如为默认实例添加一些自定义字段或方法。

typescript 复制代码
// types/axios.d.ts

import 'axios';

declare module 'axios' {
  export interface AxiosRequestConfig {
    authToken?: string; // 自定义字段
  }
}

这个用法叫做"模块补充",它不会创建新的模块,而是向现有模块补充类型定义,常用于增强第三方库的接口。


为非 TS 文件声明模块

如果你导入了 .svg、.png、.json 这类资源文件,TypeScript 默认是无法识别这些文件的类型的,需要我们手动声明,但脚手架一般都已经添加了支持,除非你在使用刀耕火种的方式自己搭建脚手架,才需要手动自己去配置:

typescript 复制代码
// types/assets.d.ts

declare module '*.svg' {
  const src: string;
  export default src;
}

declare module '*.png' {
  const src: string;
  export default src;
}

declare module '*.json' {
  const value: any;
  export default value;
}

这样就可以正常导入图片或 JSON 文件:

javascript 复制代码
import logo from './assets/logo.svg';
import config from './config.json';

补充:declare global 用于增强全局类型

有时候还可能需要往全局作用域中注入变量或接口,例如:

typescript 复制代码
// types/global.d.ts
declare global {
  interface Window {
    $t: typeof import('vue-i18n').useI18n;
    appVersion: string;
  }
}

这种写法用于补充全局变量(例如 window.appVersion),或者为 Node.js 的全局环境(如 process.env)添加类型支持。

vite的ts智能提示

vite在使用env的时候,可以参考vite的文档cn.vite.dev/guide/env-a... ,它单独提供了一个vite-env.d.ts用来处理这种情况

csharp 复制代码
interface ViteTypeOptions {
  // 添加这行代码,你就可以将 ImportMetaEnv 的类型设为严格模式,
  // 这样就不允许有未知的键值了。
  // strictImportMetaEnv: unknown
}

interface ImportMetaEnv {
  readonly VITE_APP_TITLE: string;
  // 更多环境变量...
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

小结:declare 的三种常见用法

用法 场景
declare module 声明外部模块、虚拟模块、资源模块等
模块补充(merge) 向已存在模块(如 axios)追加字段/方法
declare global 向全局作用域注入变量、接口、类型定义

建议的结构组织方式

可以这样组织你的 types/ 目录:

csharp 复制代码
types/
├─ global.d.ts          # 全局类型接口/变量声明
├─ user.d.ts            # 业务类型拆分模块
├─ env.d.ts             # 环境变量声明
├─ modules.d.ts         # 自定义 module 声明
├─ assets.d.ts          # 资源文件模块(如 .svg/.png)
├─ axios.d.ts           # 补充第三方库模块定义

所有文件都应以 .d.ts 结尾,以确保 TypeScript 把它们当作声明文件而不是普通模块处理。


为什么要使用 declare 关键字?

  • 无需导入第三方 .d.ts 文件时,自定义模块声明。
  • 向已存在模块扩展功能时(模块合并)。
  • 为资源文件提供类型提示。
  • 向 window 或全局对象注入类型。
  • 在无需导入的前提下,让项目的类型系统更加完整、可靠。

总结

通过使用全局类型定义,可以:

  • 减少冗余的 import/export 操作
  • 简化类型引用,提高开发效率
  • 按模块拆分维护更清晰

只需:

  1. 在项目根目录添加 types/ 文件夹,写入 .d.ts 类型声明
  2. 配置 tsconfig.json 的 typeRoots 和 include
  3. 直接使用类型,无需导入!

只要是typescript项目就可以按这种方法使用。

本文仓库托管在github.com/cbtpro/vite...

相关推荐
陈随易2 小时前
Postman 被曝自动往 Claude Code 和 Codex 装插件
前端·后端·程序员
Dream-Y.ocean4 小时前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
Csvn5 小时前
性能监控
前端
Highcharts.js5 小时前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
Csvn5 小时前
构建工具
前端
FRing036 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Java小卷7 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
kyriewen8 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒8 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫9 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库