Skip to content
返回

为什么你的TypeScript项目里,总会有几个.d.ts文件?

![[../../../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一下就给你标红,说“这玩意没类型,我没法检查”。

这时候,你有两个选择:

  1. 改人家JS文件,变成

    .ts

    —— 别想,那是别的团队维护的。

  2. 写个

    .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

是不是有点“全局污染”?是。但小项目图个省事。

文件的潜规则

  1. 文件名无所谓,但最好有意义
    比如axios.d.tsenv.d.ts,一看就知道是干啥的。

  2. 内容只能是类型相关
    你不能在.d.ts里写

    const x = 1

    会报错。它只能有typeinterfacedeclare这些。

  3. declare module 是“声明模块”的万能钥匙
    第三方库没类型?用它!JS 文件想加类型?用它!

  4. 别滥用,小心“类型幻觉”
    你写了个

    declare const api: any;

    确实不报错了,但等于啥也没做。类型检查形同虚设,别骗自己。

结尾

.d.ts

文件用得好,它让你的项目更健壮;用得烂,它让你的类型系统变成 “皇帝的新衣”。





到这里就结束了,后续还会更新 Vue 系列相关,还请持续关注! 感谢阅读,若有错误可以在下方评论区留言哦!!!

![[../../../assets/images/pub/clw.webp#pic_center)]]




Share this post on:

上一篇文章
2025-08-21面试
下一篇文章
炫酷的CSS loading加载动画(拒绝废话版)