拓冰建站拓冰建站
首页 / 资讯中心 / 正文

为“类模块“编写 TypeScript 声明文件:module-class.d.ts 模板完全解析

文档教程【免费下载链接】TypeScriptTypeScript 使用手册中文版翻译。http://www.typescriptlang.org项目地址https://gitcode.com/gh_mirrors/typ/TypeScript点击查看免费下载本指南以 module-class.d.ts 模板 为主线讲解如何为导出单个类、可用new实例化的 JavaScript 模块如super-greeter编写.d.ts声明文件。读完本文你将掌握export 、export as namespaceUMD 导出、declare class与伴生declare namespace的组合用法并能在 CommonJS 与 ES 模块两种环境下正确导入此类库。本文属于声明文件模板系列建议先阅读库结构了解不同库类型的整体分类。什么时候需要这个模板在库结构一节中模块化代码库被细分为若干模式其中一种特征是模块导出的对象本身就是类构造器使用者必须通过new关键字来创建实例。例如const Greeter require(super-greeter); const greeter new Greeter(); greeter.greet();对应的判断模式是来自 library-structures.mdvar x require(bar); // Note: using new operator on the imported variable var y new x(hello);如果一个模块可以当作构造函数使用通过new调用就应该使用 module-class.d.ts 模板如果模块是当作函数调用如x(42)则应使用 module-function.d.ts如果模块导入后会修改其他模块则使用 module-plugin.d.ts。若只是导出若干方法、属性和类型的普通模块先从 module.d.ts 看起。模板完整代码将下面的内容保存为super-greeter/index.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 template file for class modules. *~ 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 that ES6 modules cannot directly export class objects. // This file should be imported using the CommonJS-style: // import x require([~THE MODULE~]); // // Alternatively, if --allowSyntheticDefaultImports or // --esModuleInterop is turned on, this file can also be // imported as a default import: // import x from [~THE MODULE~]; // // Refer to the TypeScript documentation at // https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require // to understand common workarounds for this limitation of ES6 modules. /*~ If this module is a UMD module that exposes a global variable myClassLib when *~ loaded outside a module loader environment, declare that global here. *~ Otherwise, delete this declaration. */ export as namespace myClassLib; /*~ This declaration specifies that the class constructor function *~ is the exported object from the file */ export MyClass; /*~ Write your modules methods and properties in this class */ declare class MyClass { constructor(customGreeting?: string); greet: void; myMethod(opts: MyClass.MyClassMethodOptions): number; } /*~ If you want to expose types from your module as well, you can *~ place them in this block. *~ *~ Note that if you decide to include this namespace, the module can be *~ incorrectly imported as a namespace object, unless *~ --esModuleInterop is turned on: *~ import * as x from [~THE MODULE~]; // WRONG! DO NOT DO THIS! */ declare namespace MyClass { export interface MyClassMethodOptions { width?: number; height?: number; } }逐段拆解模板文件头注释命名与占位符模板头部以注释形式给出三个占位符发布到 npm 前应替换为真实信息[~THE LIBRARY NAME~] [~OPTIONAL VERSION NUMBER~]库名与可选版本号[~THE PROJECT NAME~]项目名[~YOUR NAME~] [~A URL FOR YOU~]作者署名与主页。文件必须重命名为index.d.ts并放在与模块同名的目录中。例如为super-greeter编写类型时路径是super-greeter/index.d.ts。发布声明文件的具体流程参见发布到 npm。export as namespace声明 UMD 全局变量export as namespace myClassLib;export as namespace用于声明UMD 模块。UMD 库既能在模块加载器环境中通过import/require使用也能在纯浏览器script场景下暴露为全局变量。此处的myClassLib就是在没有模块加载器的环境中可访问的全局变量名。判断一个库是否是 UMD可参考 library-structures.md 中的特征源码顶部往往出现typeof define、typeof window或typeof module之类的环境检测例如(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) {如果目标库不是UMD即只能通过模块加载器使用模板注释明确要求删除export as namespace这一行。export 把类构造器作为模块导出对象export MyClass;这是本模板的核心。TypeScript 提供export 语法来兼容 CommonJS/AMD 的exports赋值模式——即模块整体导出的是一个对象而这个对象可以是类、接口、命名空间、函数或枚举参见模块参考手册。对于本模板而言export 的含义是模块导出的就是MyClass这个类构造器本身。于是require(super-greeter)拿到的值可以直接被newconst Greeter require(super-greeter); const greeter new Greeter();declare class描述类的形状declare class MyClass { constructor(customGreeting?: string); greet: void; myMethod(opts: MyClass.MyClassMethodOptions): number; }declare class在.d.ts中声明类的类型形状不产生任何运行时代码。这里展示了三个要点构造函数constructor(customGreeting?: string)表示构造时可传入可选的问候语字符串对应new Greeter()与new Greeter(Hello)两种用法属性greet: void;声明实例属性。注意模板原文此处写得比较简略——在实际的声明文件中方法应写为greet(): void;这样的方法签名属性则用readonly、?:等修饰符精确描述可变性方法引用伴生类型myMethod(opts: MyClass.MyClassMethodOptions)中的MyClass.MyClassMethodOptions通过类 命名空间同名合并来引用下面declare namespace MyClass中定义的类型。declare namespace伴生类型与命名合并declare namespace MyClass { export interface MyClassMethodOptions { width?: number; height?: number; } }declare namespace与declare class同名合并是声明文件中的经典技巧类的实例成员写在declare class里而模块附带暴露的接口、类型别名等写在declare namespace里。这样既能让myMethod的参数类型指向MyClass.MyClassMethodOptions也允许使用者在类型位置直接书写MyClass.MyClassMethodOptions与库的运行时结构保持一致。接口中的width?: number; height?: number;均为可选属性表明调用方可以只传部分选项。如何导入这个模块CommonJS 风格推荐、必选由于 ES6 模块无法直接导出类对象模板注释明确要求使用 TypeScript 特有的导入语法import x require([~THE MODULE~]);结合export 的声明x的类型就是MyClass类本身可以直接实例化import Greeter require(super-greeter); const greeter new Greeter(); greeter.myMethod({ width: 10, height: 20 });import require与export 是配套使用的语法详见模块参考手册。开启esModuleInterop后的默认导入模板注释还给出了第二条路径当编译选项--esModuleInterop对应 tsconfig.json 中的esModuleInterop: true或--allowSyntheticDefaultImports开启时可以用默认导入import x from [~THE MODULE~];这是模板 TODO 中提到的同时给出 CommonJS 与 ES 模块两种示例的诉求esModuleInterop会让编译器自动把export 的导出包装成可默认导入的形式。相关机制在库结构中也有说明——有些模块加载器会自动检测这种情况并且将顶层对象替换为default导出而 TypeScript 在开启esModuleInterop后会替你处理。绝对不要这样写import * as x from [~THE MODULE~]; // WRONG! DO NOT DO THIS!模板用醒目的WRONG! DO NOT DO THIS!警告不要用命名空间导入import * as方式导入export 的类模块。原因在于export 导出的本质是一个值类构造器而import * as期望的是一组具名导出的命名空间对象。除非开启--esModuleInterop否则这种写法会把类错误地当成命名空间对象导致类型不匹配。同理import { myMethod } from super-greeter这类具名导入也是不合法的——本模板导出的唯一对象就是类本身。与其他模板的边界场景使用模板典型用法模块整体可被new实例化module-class.d.tsnew x(hello)模块整体可被当作函数调用module-function.d.tsx(42)模块导入后修改其他模块module-plugin.d.tsrequire(jest-matchers-files)导出多个函数、属性与类型module.d.tsimport { myField } from yourModule对比 module-function.d.ts 可以看到函数模块使用declare function可含多个重载搭配declare namespace描述返回类型与模块属性如defaultName、defaultLength而类模块使用declare class描述构造器与实例成员。两者在外层结构上完全一致——都是export as namespaceexport declare声明 同名declare namespace——区别只在导出的实体是函数还是类。常见错误与最佳实践结合最佳实践与模板本身的警告为类模块写声明文件时要注意保持类模板特有结构export MyClass;与declare class MyClass { ... }必须配套且类名需与export 右侧一致不要遗漏伴生命名空间的合并模板中MyClass.MyClassMethodOptions的写法依赖declare namespace MyClass的存在若删除该命名空间myMethod的参数类型也要一并改为不依赖它的写法不用Number/String等装箱类型构造参数customGreeting?: string应使用小写原始类型string、number避免使用String、Number等装箱对象类型do-s-and-don-ts.md按需声明 UMD 全局export as namespace myClassLib;中的全局名应与库在浏览器端实际暴露的全局变量一致若库并非 UMD应删除该行为可选选项使用可选属性MyClassMethodOptions中width、height标为可选?比单独书写多个重载更符合 TypeScript 的重载与可选参数约定。小结module-class.d.ts 模板以export declare class 同名declare namespace为三根支柱精确描述了导出单个可实例化类的模块形态export as namespace则赋予它在浏览器全局环境下的兼容性。为这类模块编写声明文件时只要保证类构造器是模块的唯一导出、并在伴生命名空间中收纳相关选项类型使用者就能在 CommonJS 与开启esModuleInterop后的ES 模块环境下获得完整的类型检查体验。后续若需将声明文件发布到 npm请继续阅读发布指南。赞分享文档教程【免费下载链接】TypeScriptTypeScript 使用手册中文版翻译。http://www.typescriptlang.org项目地址https://gitcode.com/gh_mirrors/typ/TypeScript点击查看免费下载相关推荐TypeScript 模块插件声明文件编写指南module-plugin.d.ts 模板深度解析TypeScript 模块插件声明文件编写指南module plugin.d.ts 模板深度解析 本指南围绕 TypeScript 中文手册声明文件章节中的文档教程TypeScript 声明文件模块模板 module.d.ts为模块化代码库编写类型定义的完整指南TypeScript 声明文件模块模板 module.d.ts为模块化代码库编写类型定义的完整指南 在 TypeScript 生态中为 JavaScript文档教程TypeScript 声明文件模板深度解析为全局代码库编写 global.d.tsTypeScript 声明文件模板深度解析为全局代码库编写 global.d.ts 本文是 TypeScript 使用手册中文版声明文件·模板系列的技文档教程上一篇MediaPipe 迁移指南从 Legacy Solutions 到 Tasks API这 4 处改动就够下一篇6G显存跑大模型ChatGLM-6B-INT4的轻量化革命与选型指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门