Skip to content

dts 声明文件、内置 API 与常见错误

顺序为:类型声明 → 内置工具类型提要 → 示例 → 常见错误排查。


第一部分:dts 类型声明文件

要点速览

shell
# 总结
*.d.ts = 纯类型文件,无业务代码,只做编译时校验,无运行代码

# 核心作用
1. 补充缺失类型
第三方库无 @types/xxx 类型、老旧 JS 库、全局脚本,手动补类型,消除 any、红报错。

2. 挂载全局类型
不用到处 import,整个项目全局生效。

3. 扩展原生内置类型
扩展 Window、Date、Array、CSS、React 内置类型。

4. 声明静态资源模块
 TS 识别 svg/png/less/scss/mp3 等导入,避免引入资源报错。

5. 统一项目公共类型
全局通用接口、枚举、工具类型统一管理。

# 生效条件 tsconfig.json 正确配置包含路径
{
  "include": ["src/**/*", "src/typings/**/*"]
}

# 全局/局部类型声明文件
全局类型声明文件:在 *.d.ts 文件内,要么写 declare global {},要么文件无 import /export,视为全局模块
局部类型声明文件:在 *.d.ts 文件内,有 export {} 出现一次,整个文件会变成模块文件,全局失效

常用 API

shell
declare:核心关键字,用于声明 “外部存在的变量 / 函数 / 类”,告诉 TS 编译器 “这个东西已经在别处定义了,你不用管实现,只需要知道类型”
export/import:将声明导出为模块(否则为全局声明)
declare module:声明 “非标准模块”(如图片、CSS 文件)或 “无类型的第三方库” 的类型。
declare global:在模块内扩展全局类型(比如给 window 对象加属性)。

全局类型声明文件实战

js
/******* 1. 为无类型第三方库做模块声明 *******/
某些小众库没有类型包手动声明
declare module 'xxx-utils' {
  export function formatTime(time: number): string;
}

/******* 2. 声明全局常量 / 变量 *******/
全局任意文件直接使用 APP_ENVwindow.$message 有类型提示
// 全局常量(无 import/export 的 .d.ts 中声明为全局)
declare const APP_ENV: string;
declare const VERSION: number;
// 或者 挂载到 Window 对象
interface Window {
  $message: (msg: string) => void;
  sdk: Record<string, any>;
}

/******* 3. 扩展原生内置类型 *******/
给原生对象追加自定义属性 / 方法
// 扩展 String 原型方法
interface String {
  format: () => string;
}
// 扩展 React 全局属性
declare module 'react' {
  interface HTMLAttributes<T> {
    customAttr?: string;
  }
}

/******* 4. 识别静态资源(99% 项目必备) *******/
解决import logo from '@/assets/logo.png' TS 爆红
declare module '*.png';
declare module '*.jpg';
declare module '*.jpeg';
declare module '*.svg';
declare module '*.gif';
declare module '*.scss';
declare module '*.less';
declare module '*.css';

/******* 5. 全局公共类型(无需 import) *******/
整个项目直接用 ResDataNullable无需引入
declare global {
  type ResData<T = any> = {
    code: number;
    data: T;
    message: string;
  };
  type Nullable<T> = T | null | undefined;
}

局部类型声明文件

也叫模块类型声明文件

ts
// 在 src/utils/test.d.ts 中定义
export interface UserInfo {
  id: number
  name: string
  avatar: string
  role: 'admin' | 'user' | 'guest'
}


// 在 src/utils/test.ts 中使用
import type { UserInfo } from './test.d'
export const user: UserInfo = {
  id: 100,
  name: 'alias',
  avatar: 'xxx.png',
  role: 'admin'
}

使用场景

除了上方的全局/局部类型声明文件外,还有:扩展 window 对象、处理无类型定义的第三方模块、声明非 JS/TS 文件模块

  • 扩展 window 对象
ts
// 声明 window 上的自定义属性
declare global {
  interface Window {
    // 扩展 window 的类型,添加自定义属性
    userInfo: {
      id: number;
      name: string;
    };
  }
}

// 使用
window.userInfo = { id: 1, name: "张三" }; // TS 识别该属性,无报错
  • 第三方库的类型补充(此法只用于 npm 安装的第三方库)
ts
/********************* 在 xxx-utils.d.ts 类型声明文件中拓展 ************************/

// 声明整个模块的类型(比如导入一个名为 "xxx-utils" 的无类型库)
declare module "xxx-utils" {
  // 声明模块导出的方法
  export function formatDate(date: Date): string;
  // 声明模块导出的常量
  export const PI: number;
}

// 使用
import { formatDate, PI } from "xxx-utils";
console.log(formatDate(new Date())); // TS 有类型提示

/********************* 或者 在 脚本 文件中拓展 ************************/

// src/types/axios.d.ts
import axios from 'axios';

// 扩充 axios 模块的类型
declare module 'axios' {
  // 为 AxiosRequestConfig 新增自定义配置项
  interface AxiosRequestConfig {
    showLoading?: boolean; // 新增是否显示加载的配置
  }
}

// 业务代码中使用(TS 能识别 showLoading)
axios.get('/api/data', { showLoading: true });
  • 声明非 JS/TS 文件模块(如图片、CSS)
ts
// src/typings.d.ts(项目通用类型声明文件)
declare module "*.png"; // 声明 png 图片模块,导出默认值为字符串(图片路径)
declare module "*.jpg";
declare module "*.css" {
  // 声明 CSS 模块,导出键值对(CSS Modules 场景)
  const styles: { [key: string]: string };
  export default styles;
}

// 使用
import logo from "./logo.png";
import styles from "./index.css";

目录结构规范

shell
src/
├── types/          # 全局/公共类型目录
   ├── global.d.ts # 全局类型(扩展 Window、Array 等)
   ├── common.d.ts # 公共类型(如 BaseResponse、Pagination)
   └── modules/    # 第三方库的类型声明(如 xxx-sdk.d.ts)
├── utils/
   ├── utils.js    # JS 工具库
   └── utils.d.ts  # 对应 JS 文件的类型声明
└── tsconfig.json

tsconfig.json 配置

json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
    "skipLibCheck": true,
    "typeRoots": ["./node_modules/@types", "./types"],
    "types": ["vite/client"],
    "plugins": [{ "name": "typescript-plugin-css-modules" }],
    "noImplicitAny": false,
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue","types/**/*"]
}

注意事项

  1. 第一点:TS 会自动扫描项目中的 .d.ts 类型声明文件,扫描的范围在 tsconfig.json 中配置
  2. 第二点:TS 中全局和局部声明文件与取名无关,关键在于是否有任何的 import/export 语句。有则整个文件为局部,没有则为全局
  3. 第三点:全局文件的另一种写法,将类型声明定义在 declare global {} 中,在文件的最后必须使用 export {}

第二部分:TS 内置 API(汇总)

.md`)

总结

shell
# 建议掌握(常见)
Pick/Omit/Partial/Required/Record/Exclude/Extract/ReturnType/Parameters 覆盖 80% 基础场景;

# 掌握(进阶)
Awaited/NonNullable/InstanceType/OmitThisParameter 处理函数、异步、类的场景;

# 了解(高级)
模板字面量工具(Uppercase 等)、TS5.0+ 新工具

# 避坑(版本兼容)
部分工具类型是 TS 高版本新增的,低版本使用会报错,核心版本新增如下:
TS4.1+:模板字面量工具(Uppercase/Capitalize 等)、具名元组
TS4.5+:Awaited(解析 Promise)
TS5.0+:TupleToUnion(元组转联合)
TS5.2+:CallableFunction/NewableFunction(替代 Function)
TS5.4+:ReadonlyRecord/ReadonlyTuple(只读 Record / 元组)
建议项目中使用 TS5.0+ 版本,可使用所有核心工具类型,同时获得更好的类型推断性能。

对象属性操作

最常用的维度,覆盖对象属性的保留、排除、可选 / 必选、只读、键值映射

shell
Pick              Pick<T, K> T 中仅保留指定属性 K(K T 的属性联合)
Omit              Omit<T, K> T 中排除指定属性 K(Pick 反向,底层 Pick+Exclude) 
Partial           Partial<T> T 的所有顶层属性变为可选(?) 
Required          Required<T> T 的所有顶层可选属性变为必选(移除 ?,Partial 反向) 
Readonly          Readonly<T> T 的所有顶层属性变为只读(readonly)
Record            Record<K, T>             创建新对象类型,属性名为 K(联合类型),属性值均为 T 类型 
ReadonlyRecord    ReadonlyRecord<K, T>     TS5.4+版本,等价于 Readonly<Record<K, T>>,创建只读的 Record

联合类型操作

作用于联合类型,实现「排除、提取、过滤」

shell
Exclude         Exclude<T, U>       从联合类型 T 中排除属于 U 的部分(取差集)
Extract         Extract<T, U>       从联合类型 T 中提取属于 U 的部分(取交集,Exclude 反向)
NonNullable     NonNullable<T>      从联合类型 T 中排除 null undefined

函数类型操作

专门处理函数类型,覆盖参数、返回值、this 上下文、重载的类型改造

shell
Parameters               Parameters<T>              获取函数 T 的参数类型,返回元组类型(参数顺序一致)
ConstructorParameters    ConstructorParameters<T>   获取构造函数 T 的参数类型,返回元组类型(new 调用的函数) 
ReturnType               ReturnType<T>              获取函数 T 的返回值类型 
InstanceType             InstanceType<T>            获取构造函数 T new 实例化后的类型 
OmitThisParameter        OmitThisParameter<T>       剔除函数 T 声明的this 上下文参数 
ThisParameterType        ThisParameterType<T>       获取函数 T 声明的this 上下文类型(无则返回 unknown) 
Awaited                  Awaited<T>                 TS4.5+,解析Promise 的返回值类型(支持嵌套 Promise)
CallableFunction         CallableFunction           TS5.2+,表示所有可调用函数的基础类型(替代 Function) const fn: CallableFunction = ()=>123
NewableFunction          NewableFunction            TS5.2+,表示所有可构造函数的基础类型(new 调用)

数组 / 元组类型操作

针对数组、元组的类型改造,实现「只读、元素类型提取、元组转联合」等,TS5.0+ 新增了元组专用工具,功能更强大。

shell
ReadonlyArray    ReadonlyArray<T>     创建只读数组类型,禁止增删改(等价于 readonly T[]) 
ReadonlyTuple    ReadonlyTuple<T>     TS5.4+,创建只读元组类型(严格保留元组长度和顺序) 
TupleToUnion     TupleToUnion<T>      TS5.0+,将元组类型转为联合类型(提取所有元素类型) 
ArrayLike        ArrayLike<T> 表示类数组类型(含 length 属性,索引访问),如 DOM NodeList

字符串字面量 - 大小写进一步限制

TS4.1+ 新增的模板字面量类型配套工具

shell
Uppercase       Uppercase<T>     将字符串字面量 T 转为大写       type T = Uppercase<'name'> 'NAME'
Lowercase       Lowercase<T>     将字符串字面量 T 转为小写       type T = Lowercase<'ID'> 'id'
Capitalize      Capitalize<T>    将字符串字面量 T 的首字母大写    type T = Capitalize<'name'> 'Name'
Uncapitalize    Uncapitalize<T>  将字符串字面量 T 的首字母小写    type T = Uncapitalize<'ID'> 'iD'

特殊类型

覆盖任意类型、未知类型的基础声明,适合做通用函数入参、返回值的兜底类型,日常开发中直接使用类型名即可,无需泛型。

shell
any        任意类型,关闭 TS 类型检查(慎用) 临时兼容第三方无类型代码
unknown    未知类型,比 any 安全(需类型断言 / 判断后使用) 通用函数入参兜底
never      永不存在的类型(如死循环函数返回值、联合类型排除后) 错误处理、类型守卫
void       无返回值(函数返回 undefined / return) 无返回值的函数
object     非原始类型(排除 string/number/boolean/symbol/null/undefined) 接收对象 / 数组 / 函数的入参
Function   所有函数的基础类型(TS5.2+ 推荐用 CallableFunction 替代) 接收任意函数的入参

第三部分:TS 内置 API(示例)

.md`)

Omit、Pick、Exclude、Partial、Required、、、、

Omit<Type, Keys>:从对象类型中排除指定属性,生成新类型

ts
1. Omit<Type, Keys> TS 内置工具类型核心是从对象类型中排除指定属性生成新类型

2. 语法上支持排除单个 / 多个属性多个属性用联合类型|拼接
interface User {
  id: number;
  name: string;
  age: number;
  password: string;
}
// 排除单个属性:剔除 password,UserWithoutPwd 类型:{ id: number; name: string; age: number; }
type UserWithoutPwd = Omit<User, 'password'>;
// 排除多个属性:剔除 id 和 password,UserInfo 类型:{ name: string; age: number; }
type UserInfo = Omit<User, 'id' | 'password'>;

3. 底层基于 Pick + Exclude 实现是映射类型的典型应用
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
keyof T获取原始对象类型 T 的所有属性名的联合类型
Exclude<keyof T, K> T 的属性联合类型中剔除要排除的属性 K得到保留的属性联合类型
Pick<T, ...> T 中保留上一步得到的属性最终生成新类型

4. Pick 反向
// 保留 id 和 name → 反向的 Omit<User, 'age'|'password'>
type PickUser = Pick<User, 'id' | 'name'>;

5. Exclude 作用对象不同
Exclude<T, U>作用于联合类型剔除 T 中属于 U 的部分值层面);
Omit<T, U>作用于对象类型剔除 T 中指定属性属性层面), Omit 底层是通过 Exclude 实现的
// Exclude 示例:从联合类型中剔除 'age'
type Keys = Exclude<'id'|'name'|'age', 'age'>; // 'id' | 'name'

6. 仅处理顶层属性嵌套对象的属性排除需要嵌套使用 Omit
若原始类型是嵌套对象Omit 无法直接排除嵌套对象中的属性需要结合嵌套的 Omit 处理
interface User {
  id: number;
  info: { age: number; address: string };
}
// 错误:Omit 只能排除顶层的 id/info,无法直接排除 info.address
type UserWithoutAddress = Omit<User, 'address'>;

// 正确做法:嵌套 Omit 处理嵌套属性
type UserWithoutAddress = Omit<User, 'info'> & {
  info: Omit<User['info'], 'address'>;
};
// UserWithoutAddress 类型:{ id: number; info: { age: number; } }

7. 可与其他工具类型Partial/Required组合使用
// 先剔除 password,再让所有属性变成可选
type PartialUser = Partial<Omit<User, 'password'>>;
const pUser: PartialUser = { name: '李四' }; // 正确,所有属性可选

第四部分:TS 常见错误

TS 项目四大常见报错 + 根治方案

要点速览

shell
找不到模块:补 @types + env.d.ts 声明模块 + 配置 paths
类型不匹配:定义接口约束、类型断言、关闭隐式 any
DOM 元素报错:断言为 HTMLxxxElement、非空判断
全局变量未定义:扩展 Window 接口、declare 全局常量
全是 Vue3/React 日常必遇问题

找不到模块

shell
# 报错
Cannot find module 'xxx' or its corresponding type declarations.
Could not find a declaration file for module 'xxx'.

# 原因
第三方库缺少 *.d.ts 类型声明;
tsconfig 路径别名未配置;
引入后缀缺失(.vue/.svg/.json)TS 不识别。

# 解决
1. 安装 type
npm i @types/xxx -D
2. 自定义 .d.ts 定义确实类型
3. 定义全局类型声明文件 src/env.d.ts 定义文件类型
declare module 'xxx'
declare module '*.vue'
declare module '*.svg'
declare module '*.png'
declare module '*.json'
4. 找不到配置别名
{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

DOM 元素类型

shell
# 报错
Element | null 不能调用方法
Property 'value' does not exist on type 'Element'

# 原因
document.getElementById / querySelector 返回值默认:Element | null,无具体标签属性

# 解决
1. 类型断言(最常用)
const input = document.getElementById('input') as HTMLInputElement
input.value = '' # 正常


2. Vue3 模板 Ref 元素类型  # 模板绑定:ref="inputRef"
const inputRef = ref<HTMLInputElement | null>(null)

全局变量未定义

shell
# 报错
Cannot find name 'window.xxx'
Property '$message' does not exist on type 'Window & typeof globalThis'

# 原因
挂载全局变量、全局方法、全局常量、Window 扩展属性。

# 解决
1. 根治方案(统一写在 src/env.d.ts),扩展 Window 全局类型
interface Window {
  # 自定义全局变量
  BASE_URL: string
  $message: (msg: string) => void
}

2. 全局无声明变量
declare const __ENV__: string
declare const process: {
  env: Record<string, string>
}

通用兜底 快速消错(应急)

js
1. 单行忽略
// @ts-ignore
xxx.abc

2. 宽泛类型兜底
let data: any = 接口数据

3. tsconfig 宽松配置
{
  "compilerOptions": {
    "noImplicitAny": false,
    "skipLibCheck": true
  }
}