今天咱们来啃个硬骨头:怎么写.d.ts文件。这玩意儿是TypeScript和纯JavaScript世界握手的桥梁,也是你给自己写的JS库穿上类型“外衣”的唯一方法。搞明白了,你就能给任何没有类型的代码加上安全护栏。
![图片[1]-如何编写类型声明文件(.d.ts)?-速码派](http://www.sumapai.com/wp-content/uploads/2026/01/4264fa4b7fd2477d8a2921a1403d4bebtplv-tb4s082cfz-aigc_resize_1080_1080-1.webp)
首先得搞清楚,.d.ts文件里不写具体实现,只写类型声明。它的核心任务就是告诉TypeScript:“世界上存在这么个东西,它长这个样子,你放心用。” 比如你有个用JS写的小工具函数:
// utils.js
function greet(name) {
return `Hello, ${name}!`;
}
为了让TS认识它,你在同目录下创建一个utils.d.ts:
declare function greet(name: string): string;
这就成了。现在在TS文件里import { greet } from './utils',name参数就会被检查必须是字符串,返回值也知道是字符串,智能提示全都有了。
声明变量和模块也很常见。假设你在HTML里通过<script>标签引入了一个全局变量GLOBAL_CONFIG:
declare const GLOBAL_CONFIG: {
apiUrl: string;
debug: boolean;
};
对于整个模块(比如一个npm包)的类型定义,你需要用module或者namespace关键字。最常见的是处理那些没有自带类型的第三方库:
declare module 'that-old-js-lib' {
export function doSomething(input: number): string;
export const version: string;
}
这样,你import * as lib from 'that-old-js-lib'的时候,lib.doSomething和lib.version就有类型了。
接口和类型别名的声明跟普通.ts文件里写的一模一样,直接搬过去就行。但.d.ts里有个特别有用的东西:全局扩展。你想给像window或者Array这种已有的全局对象加点自定义属性,就得在声明文件里这么写:
declare global {
interface Window {
myCustomTool: () => void;
}
interface Array<T> {
myCustomFilter(): T[];
}
}
这个declare global块告诉TS,这些声明是扩展到全局作用域的。写完之后,你项目里任意地方的window.myCustomTool或[].myCustomFilter类型都对了。
写的时候有几个细节容易踩坑。第一,声明函数重载时,顺序很重要,TS会从上往下尝试匹配。第二,尽量使用更精确的类型,别动不动就any,那等于白写。第三,对于复杂的对象结构,优先用interface声明,因为它支持声明合并,后续扩展更灵活。
最后说说怎么让TS找到你的声明文件。最简单的是直接放在源码旁边(像utils.js和utils.d.ts),TS会自动识别。如果是给整个项目用的全局类型,可以放在项目根目录,并确保它在tsconfig.json的include路径里。如果是给npm包用的,那就要把声明文件放在包的根目录,并在package.json里用"types": "index.d.ts"字段指明入口。
这东西刚开始写可能觉得有点绕,多写几次就顺手了。关键是理解它的本质:它是一份写给编译器的“类型说明书”,不负责运行,只负责描述。

























暂无评论内容