![[../../../assets/images/pub/rzyd.webp]]
刚写TS那会儿,我看到项目里莫名其妙冒出个types.d.ts 或者global.d.ts
心里是有点懵的。啥?这文件是干啥的?我
.ts文件不是已经写类型了吗?为啥还要多此一举?
后来,项目越做越大,第三方库用得越来越多,加上团队里有人用JS、有人用TS,我才发现——.d.ts
文件,其实是个“救火队员”。

一、啥时候你会突然需要
.d.ts
?
先说个场景。
我们团队之前接入了一个老系统,人家封装了个JS工具库,叫
legacy-utils.js
,里面一堆函数:
// legacy-utils.js
function formatDate(date) {
return date.toISOString().slice(0, 10);
}
function calculateTax(amount, rate) {
return amount * rate * 0.01;
}
我们在TS项目里直接 import:
import { formatDate } from './legacy-utils';
formatDate(new Date()); // 报错:Could not find a declaration file...
红了! VSCode一下就给你标红,说“这玩意没类型,我没法检查”。
这时候,你有两个选择:
-
改人家JS文件,变成
.ts—— 别想,那是别的团队维护的。
-
写个
.d.ts文件,告诉TypeScript:“别慌,我知道它有啥类型。”
于是,我默默在项目里建了个
types/legacy-utils.d.ts
⬇️
// types/legacy-utils.d.ts
declare module 'legacy-utils' {
export function formatDate(date: Date): string;
export function calculateTax(amount: number, rate: number): number;
}
然后,在
tsconfig.json
里确保
typeRoots
包含了
types
目录。
再回到代码里,红波浪线没了,自动补全也有了,世界清净了。
**那一刻我悟了:
.d.ts**就是给JS打“类型补丁”的。
二、还有啥场景会用到它?
场景1:全局变量?别慌,.d.ts 来兜底
有些老项目,喜欢把变量挂到window上:
// index.html
<script>
window.APP_CONFIG = { apiUrl: 'https://api.example.com' };
</script>
你在 TS 里写:
console.log(window.APP_CONFIG.apiUrl); // 类型“Window & typeof globalThis”上不存在属性“APP_CONFIG”
烦不烦?烦。
解决方法:建个
global.d.ts
⬇️
// global.d.ts
interface Window {
APP_CONFIG: {
apiUrl: string;
};
}
保存,刷新,红波浪线消失。舒服了。
我管这个叫“强行扩展”,虽然有点野路子,但项目要上线,谁还管你是不是优雅。
场景2:第三方库没提供类型?自己写!
比如你用了某个小众npm包,叫 super-fast-hash,作者没写类型,但你又不想用any
(毕竟开了noImplicitAny)。
你可以:
// types/super-fast-hash.d.ts
declare module 'super-fast-hash' {
const hash: (input: string) => string;
export default hash;
}
然后你就可以:
import hash from 'super-fast-hash';
const result = hash('hello'); // 类型正确,不报错
虽然这库可能就用一次,但至少代码看起来“专业”了点,对吧?
场景3:我想在多个文件里用同一个type,但不想到处import
比如我们项目里经常用到一种“用户状态”:
type UserStatus = 'active' | 'inactive' | 'pending';
如果每个文件都import,太麻烦。不如:
// types/global-types.d.ts
type UserStatus = 'active' | 'inactive' | 'pending';
然后在
tsconfig.json
里加:
{
"compilerOptions": {
"typeRoots": ["node_modules/@types", "types"]
}
}
这样,所有 .ts 文件里都能直接用UserStatus
不用import。
是不是有点“全局污染”?是。但小项目图个省事。
文件的潜规则
-
文件名无所谓,但最好有意义
比如axios.d.ts、env.d.ts,一看就知道是干啥的。 -
内容只能是类型相关
你不能在.d.ts里写const x = 1会报错。它只能有
type、interface、declare这些。 -
declare module 是“声明模块”的万能钥匙
第三方库没类型?用它!JS 文件想加类型?用它! -
别滥用,小心“类型幻觉”
你写了个declare const api: any;确实不报错了,但等于啥也没做。类型检查形同虚设,别骗自己。
结尾
.d.ts
文件用得好,它让你的项目更健壮;用得烂,它让你的类型系统变成 “皇帝的新衣”。
到这里就结束了,后续还会更新 Vue 系列相关,还请持续关注!
感谢阅读,若有错误可以在下方评论区留言哦!!!
![[../../../assets/images/pub/clw.webp#pic_center)]]