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_ENV、window.$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) *******/
整个项目直接用 ResData、Nullable,无需引入。
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.jsontsconfig.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/**/*"]
}注意事项
- 第一点:TS 会自动扫描项目中的 .d.ts 类型声明文件,扫描的范围在 tsconfig.json 中配置
- 第二点:TS 中全局和局部声明文件与取名无关,关键在于是否有任何的 import/export 语句。有则整个文件为局部,没有则为全局
- 第三点:全局文件的另一种写法,将类型声明定义在 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
}
}