14. 声明文件Declaration Files1. 概述声明文件.d.ts文件用于描述 JavaScript 库的类型信息让 TypeScript 能够理解和使用纯 JavaScript 编写的代码。声明文件只包含类型定义不包含实现代码。┌─────────────────────────────────────────────────────────────┐ │ 声明文件系统 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 声明文件的作用 │ │ ├── 为 JavaScript 库提供类型信息 │ │ ├── 让 TypeScript 理解全局变量 │ │ ├── 扩展现有模块的类型 │ │ └── 为项目提供统一的类型定义 │ │ │ │ 声明文件来源 │ │ ├── 内置类型TypeScript 自带lib.d.ts │ │ ├── DefinitelyTypedtypes/*包 │ │ ├── 库自带库内置类型定义 │ │ └── 自定义项目内手写声明 │ │ │ │ 声明语法 │ │ ├──declarevar声明全局变量 │ │ ├──declarefunction声明函数 │ │ ├──declareclass声明类 │ │ ├──declaremodule声明模块 │ │ ├──declarenamespace声明命名空间 │ │ └──declareglobal扩展全局类型 │ │ │ └─────────────────────────────────────────────────────────────┘2. 为什么需要声明文件2.1 没有声明文件的问题// utils.js纯 JavaScriptexportfunctionformatPrice(price,currency¥){return${currency}${price.toFixed(2)};}exportconstAPI_URLhttps://api.example.com;exportclassUser{constructor(name){this.namename;}greet(){returnHello,${this.name};}}// app.tsTypeScriptimport{formatPrice,API_URL,User}from./utils.js;// TypeScript 无法推断类型所有导入都是 any 类型constpriceformatPrice(99.9);// anyconsturlAPI_URL;// anyconstusernewUser(Alice);// any2.2 添加声明文件// utils.d.tsdeclaremodule./utils.js{exportfunctionformatPrice(price:number,currency?:string):string;exportconstAPI_URL:string;exportclassUser{constructor(name:string);name:string;greet():string;}}3. 声明语法3.1 declare var / let / const// global.d.ts// 声明全局变量declarevar__VERSION__:string;declarelet__DEBUG__:boolean;declareconst__API_URL__:string;// 声明全局函数declarefunctionlog(message:string):void;// 声明全局类declareclassGlobalService{staticinstance:GlobalService;getName():string;}3.2 declare function// 声明函数重载declarefunctioncreateElement(tag:string):HTMLElement;declarefunctioncreateElement(tag:string,props:object):HTMLElement;declarefunctioncreateElement(tag:string,props:object,...children:any[]):HTMLElement;// 声明函数属性declarefunctionfetch(url:string):PromiseResponse;declarenamespacefetch{functionpolyfill():void;constisSupported:boolean;}3.3 declare class// 声明类declareclassAnimal{constructor(name:string);name:string;speak():void;staticcreate(name:string):Animal;}// 声明抽象类declareabstractclassShape{abstractgetArea():number;getPerimeter():number;}3.4 declare module// 声明外部模块declaremodulelodash{exportfunctionchunkT(array:T[],size:number):T[][];exportfunctiondebounceTextends(...args:any[])any(func:T,wait:number):T;}// 声明模块通配符declaremodule*.css{constcontent:{[className:string]:string};exportdefaultcontent;}declaremodule*.vue{importtype{DefineComponent}fromvue;constcomponent:DefineComponent{},{},any;exportdefaultcomponent;}declaremodule*.png{constsrc:string;exportdefaultsrc;}3.5 declare namespace// 声明命名空间declarenamespaceMyLib{functiondoSomething():void;namespaceUtils{functionhelper():string;}interfaceOptions{debug:boolean;timeout:number;}}// 使用MyLib.doSomething();MyLib.Utils.helper();3.6 declare global// 扩展全局类型declareglobal{interfaceWindow{myCustomProperty:string;myAPI:{getData():Promiseany;};}interfaceArrayT{last():T|undefined;first():T|undefined;}}// 使用window.myCustomPropertyvalue;constlast[1,2,3].last();// 34. DefinitelyTyped4.1 安装类型定义# 安装 Node.js 类型npminstall--save-dev types/node# 安装 React 类型npminstall--save-dev types/react# 安装 Lodash 类型npminstall--save-dev types/lodash# 安装 Express 类型npminstall--save-dev types/express4.2 使用示例// 安装后自动可用无需额外配置import*asexpressfromexpress;import*as_fromlodash;constappexpress();// 类型正确constchunked_.chunk([1,2,3,4],2);// number[][]5. 编写声明文件5.1 为 JavaScript 库编写声明// my-library.d.ts// 假设有一个 JavaScript 库 my-library// 模块声明declaremodulemy-library{// 配置接口exportinterfaceConfig{debug?:boolean;timeout?:number;retries?:number;}// 主要函数exportfunctioninit(config:Config):void;exportfunctiongetDataT(url:string):PromiseT;exportfunctionpostDataT(url:string,data:any):PromiseT;// 类exportclassClient{constructor(config:Config);requestT(url:string):PromiseT;close():void;}// 常量exportconstversion:string;exportconstAPI_BASE:string;}5.2 为全局库编写声明// global-lib.d.ts// 假设有一个全局 JavaScript 库interfaceGlobalLibConfig{mode:development|production;apiUrl:string;}interfaceGlobalLibAPI{start():void;stop():void;getConfig():GlobalLibConfig;}// 声明全局变量declarevarGlobalLib:GlobalLibAPI;declarefunctioninitGlobalLib(config:GlobalLibConfig):void;5.3 扩展现有模块// express-extensions.d.tsimportexpress;declaremoduleexpress{interfaceRequest{user?:{id:number;name:string;role:admin|user;};startTime:number;}interfaceResponse{successT(data:T):this;error(message:string,code?:number):this;}}6. 声明文件的类型导出6.1 导出类型// types/index.d.tsexportinterfaceUser{id:number;name:string;email:string;}exporttypeUserRoleadmin|user|guest;exportconstdefaultUser:User;exportfunctioncreateUser(name:string,email:string):User;6.2 默认导出// logger.d.tsdeclareclassLogger{constructor(name:string);info(message:string):void;error(message:string):void;warn(message:string):void;}exportdefaultLogger;6.3 混合导出// utils.d.tsexportconstversion:string;exportfunctionformatDate(date:Date):string;exportfunctionformatNumber(num:number):string;exportdefault{version,formatDate,formatNumber};7. 完整示例为 API 客户端编写声明// api-client.js假设是已有的 JavaScript 代码// 1. 声明文件 // api-client.d.tsdeclaremoduleapi-client{// 请求配置exportinterfaceRequestConfig{method?:GET|POST|PUT|DELETE;headers?:Recordstring,string;timeout?:number;retries?:number;}// 响应类型exportinterfaceApiResponseTany{success:boolean;data:T;message:string;code:number;timestamp:number;}// 错误类型exportinterfaceApiError{code:number;message:string;details?:any;}// 拦截器exportinterfaceInterceptor{request?:(config:RequestConfig)RequestConfig;response?:T(response:ApiResponseT)ApiResponseT;error?:(error:ApiError)void;}// 客户端类exportclassApiClient{constructor(baseURL:string,config?:RequestConfig);getT(url:string,config?:RequestConfig):PromiseApiResponseT;postT(url:string,data?:any,config?:RequestConfig):PromiseApiResponseT;putT(url:string,data?:any,config?:RequestConfig):PromiseApiResponseT;deleteT(url:string,config?:RequestConfig):PromiseApiResponseT;addInterceptor(interceptor:Interceptor):void;removeInterceptor(interceptor:Interceptor):void;setToken(token:string):void;clearToken():void;}// 工厂函数exportfunctioncreateClient(baseURL:string,config?:RequestConfig):ApiClient;// 默认导出exportdefaultApiClient;}// 2. 使用示例 // app.tsimportApiClient,{createClient,ApiResponse}fromapi-client;interfaceUser{id:number;name:string;email:string;}// 方式1使用类constclientnewApiClient(https://api.example.com,{timeout:5000,retries:3});client.setToken(your-token);constresponseawaitclient.getUser[](/users);if(response.success){console.log(response.data);// User[]}// 方式2使用工厂函数constclient2createClient(https://api.example.com);// 添加拦截器client2.addInterceptor({request:(config){console.log(Request:,config);returnconfig;},response:(res){console.log(Response:,res);returnres;}});8. 发布类型定义8.1 package.json 配置{name:my-library,version:1.0.0,main:dist/index.js,types:dist/index.d.ts,files:[dist/**/*.js,dist/**/*.d.ts],scripts:{build:tsc,prepublishOnly:npm run build}}8.2 双包发布{name:my-library,version:1.0.0,main:dist/index.js,module:dist/index.mjs,types:dist/index.d.ts,exports:{.:{import:./dist/index.mjs,require:./dist/index.js,types:./dist/index.d.ts},./utils:{import:./dist/utils.mjs,require:./dist/utils.js,types:./dist/utils.d.ts}}}9. 常见模式9.1 条件类型导出declaremodulemy-utils{exportfunctionisString(value:unknown):valueisstring;exportfunctionisNumber(value:unknown):valueisnumber;exportfunctionisArrayT(value:unknown):valueisT[];}9.2 泛型类型导出declaremodulemy-utils{exportfunctionmapT,U(array:T[],fn:(item:T,index:number)U):U[];exportfunctionfilterT(array:T[],predicate:(item:T)boolean):T[];exportfunctionreduceT,U(array:T[],reducer:(acc:U,item:T)U,initialValue:U):U;}9.3 可调用接口declaremodulemy-utils{interfaceMyFunction{(value:string):number;version:string;config:{debug:boolean};}constmyFunction:MyFunction;exportdefaultmyFunction;}10. 总结声明类型语法用途变量declare var name: type声明全局变量函数declare function name(params): return声明全局函数类declare class Name { ... }声明全局类模块declare module name { ... }声明外部模块命名空间declare namespace Name { ... }声明命名空间全局扩展declare global { ... }扩展全局类型通配符declare module *.ext声明文件模块