如何编写类型声明文件(.d.ts)?

今天咱们来啃个硬骨头:怎么写.d.ts文件。这玩意儿是TypeScript和纯JavaScript世界握手的桥梁,也是你给自己写的JS库穿上类型“外衣”的唯一方法。搞明白了,你就能给任何没有类型的代码加上安全护栏。

首先得搞清楚,.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.doSomethinglib.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.jsutils.d.ts),TS会自动识别。如果是给整个项目用的全局类型,可以放在项目根目录,并确保它在tsconfig.jsoninclude路径里。如果是给npm包用的,那就要把声明文件放在包的根目录,并在package.json里用"types": "index.d.ts"字段指明入口。

这东西刚开始写可能觉得有点绕,多写几次就顺手了。关键是理解它的本质:它是一份写给编译器的“类型说明书”,不负责运行,只负责描述。

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 抢沙发

    暂无评论内容