资讯动态

TypeScript 全局插件声明文件编写指南:global-plugin.d.ts 模板与 UMD/全局插件识别实战

发布时间:2026/9/29 21:54:58 来源:尧图企业网站定制
文档教程【免费下载链接】TypeScriptTypeScript 使用手册中文版翻译。http://www.typescriptlang.org项目地址https://gitcode.com/gh_mirrors/typ/TypeScript点击查看免费下载本篇技术指南围绕 TypeScript 中文手册本项目仓库中 zh/declaration-files/templates/global-plugin.d.ts.md 模板文档展开系统讲解如何为修改全局对象结构的插件型代码库编写.d.ts声明文件。你将掌握 UMD 模块的识别方法、全局插件与全局修改模块的区分、declare namespace与全局接口增强的正确写法以及声明文件对全局库/模块/UMD 模块三类依赖的声明方式最终能够独立为 jQuery、Moment.js 这类生态的插件编写高质量类型定义。一、背景声明文件模板体系与本文档定位在 TypeScript 中当第三方 JavaScript 代码库没有自带类型定义时需要由社区或开发者手写.d.ts声明文件。编写的第一步是识别代码库的形态再套用对应的模板。本项目 zh/declaration-files/templates.md 共收录 7 个模板模板文件适用代码库形态global.d.ts全局代码库通过全局作用域访问无 importglobal-plugin.d.ts全局插件改变全局对象结构global-modifying-module.d.ts导入时修改全局作用域的模块module.d.ts普通模块不可调用、不可构造module-class.d.ts可用new构造的模块module-function.d.ts可当作函数调用的模块module-plugin.d.ts模块插件修改其它模块结构本指南聚焦global-plugin.d.ts同时因它与 UMD、全局修改模块、依赖声明等主题深度交织会一并展开讲解。完整脉络可参考 zh/declaration-files/library-structures.md 中识别代码库的类型一节。二、UMD同一份代码模块与全局两种用法2.1 什么是 UMD 模块一个 UMDUniversal Module Definition模块既可以用作 ES 模块使用 import 语句也可以用作全局变量在缺少模块加载器的环境中使用。许多流行的代码库如 Moment.js都以这种模式发布。在 Node.js 或使用 RequireJS 的环境中通过模块加载器导入import moment require(moment); console.log(moment.format());在纯浏览器环境中直接使用全局变量console.log(moment.format());理解 UMD 很关键很多全局插件实际是依附于 UMD 主库的。例如moment-range为moment对象添加range方法而moment本身以 UMD 形式发布——声明文件必须同时照顾两种加载路径。2.2 识别 UMD 代码库UMD 模块会在运行时检测环境中是否存在模块加载器。这是一种常见模式典型示例如下(function (root, factory) { if (typeof define function define.amd) { define([libName], factory); } else if (typeof module object module.exports) { module.exports factory(require(libName)); } else { root.returnExports factory(root.libName); } }(this, function (b) {识别要点看到typeof define、typeof window或typeof module这类检测代码尤其是出现在文件顶端时大概率是 UMD 代码库UMD 模块的文档通常会同时给出 Node.js 中require的用法和浏览器中script标签的用法——这本身就是强信号。流行的 UMD 代码库示例jQuery、Moment.js、lodash 等。2.3 UMD 的依赖声明全局库与模块库的区别编写声明文件时依赖关系决定了语法选择。规则如下你的声明文件所服务的代码库被依赖的库类型正确写法全局代码库全局库/// reference typessomeLib /全局代码库UMD 模块/// reference typesmoment /模块 / UMD 代码库模块import * as moment from moment;模块 / UMD 代码库UMD 代码库import * as someLib from someLib;对全局库使用三斜线指令/// reference typessomeLib / function getThing(): someLib.thing;对模块依赖使用importimport * as moment from moment; function getThing(): moment;对 UMD 模块的依赖要区分场景全局代码库依赖 UMD 模块时使用/// reference types指令/// reference typesmoment / function getThing(): moment;ES 模块或 UMD 模块代码库依赖 UMD 代码库时使用import语句import * as someLib from someLib;特别提醒不要使用/// reference指令来声明对 UMD 代码库的依赖——因为在模块环境下 UMD 库仍需通过导入才能正确解析其导出内容。三、模块模板的选择先判断可调用/可构造在进入全局插件之前先明确针对普通模块的三个模板因为全局插件模板常与它们组合使用。3.1 可调用模块 → module-function.d.ts若一个模块可以当作函数调用使用 module-function.d.ts 模板var x require(foo); // Note: calling x as a function var y x(42);其声明核心是export MyFunction;配合多个函数重载签名返回类型放入同名的declare namespacedeclare function MyFunction(name: string): MyFunction.NamedReturnType; declare function MyFunction(length: number): MyFunction.LengthReturnType; declare namespace MyFunction { export interface LengthReturnType { width: number; height: number; } export interface NamedReturnType { firstName: string; lastName: string; } export const defaultName: string; }3.2 可构造模块 → module-class.d.ts若一个模块可以使用new来构造使用 module-class.d.ts 模板var x require(bar); // Note: using new operator on the imported variable var y new x(hello);声明核心是export MyClass;配合declare classexport MyClass; declare class MyClass { constructor(customGreeting?: string); greet: void; myMethod(opts: MyClass.MyClassMethodOptions): number; } declare namespace MyClass { export interface MyClassMethodOptions { width?: number; height?: number; } }3.3 普通模块 → module.d.ts若一个模块既不可以调用、又不可以构造使用 module.d.ts 模板——它是理解全部模块模板的基础。普通模块用命名导出描述形状若模块在无加载器环境会暴露全局变量可附加export as namespace myLib;export as namespace myLib; export function myMethod(a: string): string; export function myOtherMethod(a: number): number; export interface someType { name: string; length: number; extras?: string[]; } export const myField: number; export namespace subProp { export function foo(): void; }脚注提醒许多代码库如 Express将自身导出为可调用函数即import exp require(express); var app exp();。但在 ES6 模块加载器中顶层模块对象永远不能被调用。最常见的解决方案是为可调用/可构造对象定义default导出若在tsconfig.json中启用了esModuleInterop: trueTypeScript 会自动处理这一转换。四、模块插件为其它模块添加新能力模块插件会改变其它模块的结构包含 UMD 或 ES 模块。例如在 Moment.js 生态中moment-range会把range方法添加到moment对象上。对声明文件编写而言无论是 ES 模块还是 UMD 模块都可以使用相同代码——使用 module-plugin.d.ts 模板// Type definitions for [~THE LIBRARY NAME~] [~OPTIONAL VERSION NUMBER~] // Project: [~THE PROJECT NAME~] // Definitions by: [~YOUR NAME~] [~A URL FOR YOU~] /*~ This is the module plugin template file. You should rename it to index.d.ts *~ and place it in a folder with the same name as the module. *~ For example, if you were writing a file for super-greeter, this *~ file should be super-greeter/index.d.ts */ /*~ On this line, import the module which this module adds to */ import * as m from someModule; /*~ You can also import other modules if needed */ import * as other from anotherModule; /*~ Here, declare the same module as the one you imported above */ declare module someModule { /*~ Inside, add new function, classes, or variables. You can use *~ unexported types from the original module if needed. */ export function theNewMethod(x: m.foo): other.bar; /*~ You can also add new properties to existing interfaces from *~ the original module by writing interface augmentations */ export interface SomeModuleOptions { someModuleSetting?: string; } /*~ New types can also be declared and will appear as if they *~ are in the original module */ export interface MyModulePluginOptions { size: number; } }关键机制先import * as m from someModule再用declare module someModule打开同名模块进行模块增强module augmentation新函数、新接口、新类型都会像原本就属于该模块一样生效。脚注ES6 对模块插件的影响一些插件会对已有模块的顶层导出进行添加或修改。这在 CommonJS 及其它模块加载器中是合法的但ES6 模块是不可改变的该模式在 ES6 下不可行。由于 TypeScript 与模块加载器无关编译时不会对此加以限制但开发者若计划迁移到 ES6 模块加载器需要格外注意。五、全局插件本文档核心模板 global-plugin.d.ts5.1 什么是全局插件全局插件是一段全局代码它会改变某个全局变量通常是改变全局对象的结构。例如有些库会向Array.prototype或String.prototype增加新函数。注意它与修改全局作用域的模块的区别全局插件直接以全局脚本形式运行没有require激活步骤而后者需要先require导入才会触发全局修改。二者都会增加运行时冲突的可能性。5.2 识别全局插件全局插件通常可以根据其文档来识别。你会看到如下示例——直接在全局环境中调用内置类型新增的方法var x hello, world; // Creates new methods on built-in types console.log(x.startsWithHello()); var y [1, 2, 3]; // Creates new methods on built-in types console.log(y.reverseAndSort());识别要点文档示例中没有require/import直接对String、Array等内置类型的实例调用非标准方法即插件往内置原型上挂新方法的典型形态。5.3 global-plugin.d.ts 模板全解使用 global-plugin.d.ts 模板完整内容如下// Type definitions for [~THE LIBRARY NAME~] [~OPTIONAL VERSION NUMBER~] // Project: [~THE PROJECT NAME~] // Definitions by: [~YOUR NAME~] [~A URL FOR YOU~] /*~ This template shows how to write a global plugin. */ /*~ Write a declaration for the original type and add new members. *~ For example, this adds a toBinaryString method with overloads to *~ the built-in number type. */ interface Number { toBinaryString(opts?: MyLibrary.BinaryFormatOptions): string; toBinaryString( callback: MyLibrary.BinaryFormatCallback, opts?: MyLibrary.BinaryFormatOptions ): string; } /*~ If you need to declare several types, place them inside a namespace *~ to avoid adding too many things to the global namespace. */ declare namespace MyLibrary { type BinaryFormatCallback (n: number) string; interface BinaryFormatOptions { prefix?: string; padding: number; } }拆解模板的两个核心手法全局接口增强interface augmentation直接对内置类型Number重新声明interface在其中追加新方法签名。TypeScript 会把同名接口的成员合并declaration merging从而让(42).toBinaryString()这类调用获得类型检查。方法带有两组重载只传opts的简写形式以及传callbackopts的回调形式。命名空间收纳类型namespace插件附带的自定义类型BinaryFormatCallback、BinaryFormatOptions不要直接散落在全局顶层而是放进declare namespace MyLibrary通过MyLibrary.BinaryFormatOptions引用。这与脚注防止命名冲突的规则完全一致详见下文。模板文件头的[~THE LIBRARY NAME~]、[~OPTIONAL VERSION NUMBER~]、[~YOUR NAME~]等占位符是发布到 DefinitelyTypedtypes/时的标准头注释格式按实际情况替换即可。六、修改全局作用域的模块需要 require 激活的副作用插件对于修改全局作用域的模块导入它们时会对全局作用域中的值进行修改。比如某个代码库当导入它时会向String.prototype添加新成员。该模式存在危险有运行时冲突的可能性但我们仍然可以为其编写声明文件。6.1 识别修改全局作用域的模块可以通过文档来识别。通常它们与全局插件类似但需要require语句来激活对全局作用域的修改。你可能看到过如下文档// require call that doesnt use its return value var unused require(magic-string-time); /* or */ require(magic-string-time); var x hello, world; // Creates new methods on built-in types console.log(x.startsWithHello()); var y [1, 2, 3]; // Creates new methods on built-in types console.log(y.reverseAndSort());识别要点文档示例中先出现不消费返回值的require(magic-string-time)即纯副作用导入随后才使用x.startsWithHello()、y.reverseAndSort()这类新增的内置方法。6.2 global-modifying-module.d.ts 模板使用 global-modifying-module.d.ts 模板。核心差异在于用declare global包裹全局增强同时该文件本身仍是模块带export因此既声明了全局副作用又保留了模块自身的导出// Type definitions for [~THE LIBRARY NAME~] [~OPTIONAL VERSION NUMBER~] // Project: [~THE PROJECT NAME~] // Definitions by: [~YOUR NAME~] [~A URL FOR YOU~] /*~ This is the global-modifying module template file. You should rename it to index.d.ts *~ and place it in a folder with the same name as the module. *~ For example, if you were writing a file for super-greeter, this *~ file should be super-greeter/index.d.ts */ /*~ Note: If your global-modifying module is callable or constructable, youll *~ need to combine the patterns here with those in the module-class or module-function *~ template files */ declare global { /*~ Here, declare things that go in the global namespace, or augment *~ existing declarations in the global namespace */ interface String { fancyFormat(opts: StringFormatOptions): string; } } /*~ If your module exports types or values, write them as usual */ export interface StringFormatOptions { fancinessLevel: number; } /*~ For example, declaring a method on the module (in addition to its global side effects) */ export function doSomething(): void; /*~ If your module exports nothing, youll need this line. Otherwise, delete it */ export {};模板要点declare global { ... }用于声明进入全局命名空间的内容或对全局已有声明进行增强模块自身的类型与值照常使用export导出若模块没有任何导出则必须保留最后一行export {};否则文件不再是模块declare global会报错若该模块同时可调用或可构造需要与 module-class / module-function 模板的模式组合使用。七、利用依赖三类依赖的声明语法对照你的代码库可能有若干种依赖本节汇总声明文件中的导入规则完整版本已在 2.3 节给出对全局库的依赖→/// reference types... /指令对模块的依赖→import语句对 UMD 模块的依赖全局代码库依赖 UMD 模块 →/// reference types... /指令模块或 UMD 代码库依赖 UMD 代码库 →import * as ... from ...不要使用/// reference指令。八、脚注全局声明的最佳实践与 ES6 兼容性8.1 防止命名冲突注意虽说可以在全局作用域内定义许多类型但强烈建议不要这样做——当一个工程中存在多个声明文件时可能会导致难以解决的命名冲突。可以遵循的一个简单规则使用代码库提供的某个全局变量来声明拥有命名空间的类型。例如如果代码库提供了全局变量cats那么这样写declare namespace cats { interface KittySettings {} }而不是在顶层平铺// at top-level interface CatsKittySettings {}这样做会保证代码库可以被转换成 UMD 模块且不会影响声明文件的使用者。这正是 global-plugin.d.ts 模板把BinaryFormatOptions等类型放进MyLibrary命名空间的原因。8.2 ES6 对模块插件的影响一些插件会对已有模块的顶层导出进行添加或修改。这在 CommonJS 以及其它模块加载器里是合法的但ES6 模块是不可改变的因此该模式在 ES6 下不可行。因为 TypeScript 是模块加载器无关的编译时不会对该行为加以限制但开发者若想要转换到 ES6 模块加载器则需要特别注意。8.3 ES6 对模块调用签名的影响许多代码库如 Express将自身导出为可调用的函数典型用法如下import exp require(express); var app exp();在 ES6 模块加载器中顶层对象此例中的exp只能拥有属性顶层的模块对象永远不能够被调用。最常见的解决方案是为可调用/可构造的对象定义一个default导出有些模块加载器会自动检测这种情况并将顶层对象替换为default导出。若在tsconfig.json里启用了esModuleInterop: trueTypeScript 会自动处理这一转换。九、代码库文件结构声明文件镜像源码目录声明文件的结构应该反映代码库源码的结构。一个代码库可以包含多个模块例如myLib ---- index.js ---- foo.js ---- bar ---- index.js ---- baz.js它们可以通过如下方式导入var a require(myLib); var b require(myLib/foo); var c require(myLib/bar); var d require(myLib/bar/baz);对应的声明文件应保持同样的目录层级发布到types/myLib时types/myLib ---- index.d.ts ---- foo.d.ts ---- bar ---- index.d.ts ---- baz.d.ts这一镜像结构原则同样适用于插件global-plugin.d.ts、module-plugin.d.ts、global-modifying-module.d.ts模板文件都应重命名为index.d.ts并放入与模块同名的目录中例如为super-greeter编写的声明应位于super-greeter/index.d.ts。十、实战流程从识别到成稿的决策链综合全文为一个插件型代码库编写声明文件的完整决策链如下判断主库形态查看代码顶端是否有typeof define/typeof module/typeof window检测 → 判定 UMD 主库判断插件形态文档示例直接使用x.startsWithHello()无 require→ 全局插件 → global-plugin.d.ts文档示例先require(xxx)再使用新增方法 → 全局修改模块 → global-modifying-module.d.ts文档示例require(plugin)后给已有模块对象添加方法 → 模块插件 → module-plugin.d.ts声明依赖按第七节的对照表选择/// reference types或import组织类型新类型一律放进以全局变量命名的declare namespace中避免全局命名冲突镜像目录按源码目录结构放置.d.ts文件插件模板重命名为index.d.ts。延伸阅读声明文件库结构总览全局库、模块、UMD、插件等全部形态的识别方法模板索引7 个模板文件的导航入口编写声明文件入门、发布声明文件、消费声明文件完整的声明文件工作流赞分享文档教程【免费下载链接】TypeScriptTypeScript 使用手册中文版翻译。http://www.typescriptlang.org项目地址https://gitcode.com/gh_mirrors/typ/TypeScript点击查看免费下载相关推荐TypeScript 模块插件声明文件编写指南module-plugin.d.ts 模板深度解析TypeScript 模块插件声明文件编写指南module plugin.d.ts 模板深度解析 本指南围绕 TypeScript 中文手册声明文件章节中的文档教程TypeScript 声明文件模板实战为修改全局作用域的模块编写 global-modifying-module.d.tsTypeScript 声明文件模板实战为修改全局作用域的模块编写 global modifying module.d.ts 导读 本篇文章聚焦 TypeScr文档教程TypeScript 声明文件模板深度解析为全局代码库编写 global.d.tsTypeScript 声明文件模板深度解析为全局代码库编写 global.d.ts 本文是 TypeScript 使用手册中文版声明文件·模板系列的技文档教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑