模块 .d.ts

将 JavaScript 与示例 DTS 进行比较

常见的 CommonJS 模式

使用 CommonJS 模式的模块使用 module.exports 来描述导出的值。例如,以下是一个导出函数和数值常量的模块

js
const maxInterval = 12;
function getArrayLength(arr) {
return arr.length;
}
module.exports = {
getArrayLength,
maxInterval,
};

这可以用以下 .d.ts 来描述

ts
export function getArrayLength(arr: any[]): number;
export const maxInterval: 12;

TypeScript playground 可以显示 JavaScript 代码的 .d.ts 等效代码。你可以 在这里尝试一下

.d.ts 语法有意看起来像 ES 模块 语法。ES 模块在 2015 年被 TC39 批准为 ES2015 (ES6) 的一部分,虽然它已经可以通过转译器使用很长时间了,但是如果你有一个使用 ES 模块的 JavaScript 代码库

js
export function getArrayLength(arr) {
return arr.length;
}

这将有以下 .d.ts 等效代码

ts
export function getArrayLength(arr: any[]): number;

默认导出

在 CommonJS 中,你可以将任何值导出为默认导出,例如,以下是一个正则表达式模块

js
module.exports = /hello( world)?/;

这可以用以下 .d.ts 来描述

ts
declare const helloWorld: RegExp;
export default helloWorld;

或者一个数字

js
module.exports = 3.142;
ts
declare const pi: number;
export default pi;

CommonJS 中的一种导出风格是导出一个函数。因为函数也是一个对象,所以可以添加额外的字段,这些字段也会包含在导出中。

js
function getArrayLength(arr) {
return arr.length;
}
getArrayLength.maxInterval = 12;
module.exports = getArrayLength;

可以用以下方式描述

ts
export default function getArrayLength(arr: any[]): number;
export const maxInterval: 12;

请注意,在您的 .d.ts 文件中使用 export default 需要 esModuleInterop: true 才能正常工作。如果您无法在项目中使用 esModuleInterop: true,例如在向 Definitely Typed 提交 PR 时,则必须使用 export= 语法。这种较旧的语法更难使用,但可以在任何地方使用。以下是使用 export= 编写上述示例的方式

ts
declare function getArrayLength(arr: any[]): number;
declare namespace getArrayLength {
declare const maxInterval: 12;
}
export = getArrayLength;

有关其工作原理的详细信息,请参阅 模块:函数,以及 模块参考 页面。

处理多个消费导入

在现代消费代码中,有很多方法可以导入模块

ts
const fastify = require("fastify");
const { fastify } = require("fastify");
import fastify = require("fastify");
import * as Fastify from "fastify";
import { fastify, FastifyInstance } from "fastify";
import fastify from "fastify";
import fastify, { FastifyInstance } from "fastify";

要涵盖所有这些情况,JavaScript 代码实际上需要支持所有这些模式。为了支持其中许多模式,CommonJS 模块需要类似于以下内容

js
class FastifyInstance {}
function fastify() {
return new FastifyInstance();
}
fastify.FastifyInstance = FastifyInstance;
// Allows for { fastify }
fastify.fastify = fastify;
// Allows for strict ES Module support
fastify.default = fastify;
// Sets the default export
module.exports = fastify;

模块中的类型

您可能希望为不存在的 JavaScript 代码提供类型

js
function getArrayMetadata(arr) {
return {
length: getArrayLength(arr),
firstObject: arr[0],
};
}
module.exports = {
getArrayMetadata,
};

可以用以下方式描述

ts
export type ArrayMetadata = {
length: number;
firstObject: any | undefined;
};
export function getArrayMetadata(arr: any[]): ArrayMetadata;

此示例非常适合 使用泛型 来提供更丰富的类型信息

ts
export type ArrayMetadata<ArrType> = {
length: number;
firstObject: ArrType | undefined;
};
export function getArrayMetadata<ArrType>(
arr: ArrType[]
): ArrayMetadata<ArrType>;

现在,数组的类型会传播到 ArrayMetadata 类型中。

导出的类型可以通过 TypeScript 代码中的 importimport type,或 JSDoc 导入 被模块的使用者重复使用。

模块代码中的命名空间

尝试描述 JavaScript 代码的运行时关系可能很棘手。当 ES 模块式语法无法提供足够的工具来描述导出时,可以使用 `namespaces`。

例如,您可能拥有足够复杂的类型来描述,因此您选择在 `。d.ts` 中对它们进行命名空间。

ts
// This represents the JavaScript class which would be available at runtime
export class API {
constructor(baseURL: string);
getInfo(opts: API.InfoRequest): API.InfoResponse;
}
// This namespace is merged with the API class and allows for consumers, and this file
// to have types which are nested away in their own sections.
declare namespace API {
export interface InfoRequest {
id: string;
}
export interface InfoResponse {
width: number;
height: number;
}
}

要了解命名空间在 `。d.ts` 文件中的工作原理,请阅读 `。d.ts` 深入探讨

可选全局使用

您可以使用 `export as namespace` 来声明您的模块将在 UMD 上下文中全局范围内可用。

ts
export as namespace moduleName;

参考示例

为了让您了解所有这些部分如何组合在一起,以下是一个参考 `。d.ts`,可以作为创建新模块时的起点。

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. 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'
*/
/*~ If this module is a UMD module that exposes a global variable 'myLib' when
*~ loaded outside a module loader environment, declare that global here.
*~ Otherwise, delete this declaration.
*/
export as namespace myLib;
/*~ If this module exports functions, declare them like so.
*/
export function myFunction(a: string): string;
export function myOtherFunction(a: number): number;
/*~ You can declare types that are available via importing the module */
export interface SomeType {
name: string;
length: number;
extras?: string[];
}
/*~ You can declare properties of the module using const, let, or var */
export const myField: number;

库文件布局

您的声明文件布局应镜像库的布局。

库可以包含多个模块,例如

myLib +---- index.js +---- foo.js +---- bar +---- index.js +---- baz.js

这些可以导入为

js
var a = require("myLib");
var b = require("myLib/foo");
var c = require("myLib/bar");
var d = require("myLib/bar/baz");

因此,您的声明文件应为

@types/myLib +---- index.d.ts +---- foo.d.ts +---- bar +---- index.d.ts +---- baz.d.ts

测试您的类型

如果您计划将这些更改提交到 DefinitelyTyped 供所有人使用,那么我们建议您

  1. node_modules/@types/[libname] 中创建一个新文件夹
  2. 在该文件夹中创建一个 index.d.ts,并复制示例
  3. 查看您的模块使用情况在哪里中断,并开始填写 index.d.ts
  4. 当您满意时,克隆 DefinitelyTyped/DefinitelyTyped 并按照 README 中的说明进行操作。

否则

  1. 在您的源代码树的根目录中创建一个新文件:[libname].d.ts
  2. 添加 declare module "[libname]" { }
  3. 将模板添加到 declare 模块的大括号内,并查看您的使用情况在哪里中断

TypeScript 文档是一个开源项目。帮助我们改进这些页面 通过发送 Pull Request

此页面的贡献者
MHMohamed Hegazy (53)
OTOrta Therox (15)
MFMike Frysinger (1)
Hhzrong (1)
GSGuilherme Samuel (1)
4+

上次更新时间:2024 年 3 月 21 日