TypeScript 如何创建自己类型定义文件(.d.ts)
TypeScript是JavaScript的超集,提供了静态类型功能,可以提高代码质量并在编译期间捕获错误。为了充分利用TypeScript的静态类型特性,在项目中使用的外部JavaScript库和模块应该有类型定义文件(.d.ts)。这些类型定义文件描述了外部实体暴露的类型和接口,使得TypeScript编译器能够理解它们的形状和行为。
在本文中,我们将逐步介绍如何创建自定义的TypeScript类型定义文件,使开发人员能够在项目中受益于静态类型。
先决条件
类型定义文件(.d.ts)作为JavaScript代码和TypeScript编译器之间的接口。它们描述了JavaScript库或框架中存在的类型、函数、类和模块。这些文件使得TypeScript编译器能够进行类型检查,并在IDE中提供丰富的智能感知支持。
在开始创建类型定义文件之前,请确保您已经准备好了以下先决条件:
- 对TypeScript有基本的了解。
-
在您的系统上全局安装了TypeScript。您可以使用npm安装,命令如下:
npm install -g typescript
第一步:确定库的结构
为了创建一个类型定义文件,你需要了解你要为其创建类型定义的库或模块的结构。这涉及分析 JavaScript 代码,理解暴露的函数、类、对象及其相应的类型。
第二步:从空的 .d.ts 文件开始
创建一个空的 .d.ts 文件,文件名与你要为其创建类型定义的 JavaScript 库或模块同名。例如,如果你的库叫做 “my-library”, 那么类型定义文件应该命名为 “my-library.d.ts” 。
第三步:声明模块
创建类型定义文件的第一步是使用 declare module 语法声明模块。这告诉 TypeScript 你正在为特定的模块或库定义类型。下面是一个示例 −
declare module 'my-library' {
// Type definitions go here
}
第四步:定义类型和接口
在模块声明中,您可以定义描述库结构的类型和接口。您可以为对象声明接口,为函数声明类型等等。
让我们考虑一个例子,我们有一个名为 “math-library” 的库,其中有一个名为 “add” 的函数,它接受两个数字作为参数,并返回它们的和。
declare module 'math-library' {
export function add(a: number, b: number): number;
}
在上面的例子中,我们声明了一个名为”math-library”的模块,并导出了一个函数 add ,该函数需要两个参数 a 和 b ,并返回一个数字。
第五步: 导出类型和接口
为了使定义的类型和接口对其他TypeScript文件可用,你需要显式地将它们导出。在每个类型或接口声明之前使用 export 关键字导出它们。下面是一个扩展我们之前的 math-library 例子的示例:
declare module 'math-library' {
export function add(a: number, b: number): number;
export interface Calculator {
name: string;
add(a: number, b: number): number;
}
}
在更新的示例中,我们导出了一个称为 Calculator 的新接口,它具有一个 name 属性 和 一个具有与我们之前定义的 add 函数相同签名的方法。
第六步:使用环境声明
环境声明允许您为没有特定于TypeScript的注释的现有JavaScript代码描述类型。它们包含在一个 declare global 块中。这是一个示例−
declare global {
interface Array<T> {
filter(callbackfn: (value: T, index: number, array: T[]) => boolean): T[];
}
}
在上面的示例中,我们声明了一个全局接口 Array
第七步:引用外部类型定义(可选)
如果您的类型定义文件依赖于其他外部类型定义文件,您可以使用 /// < reference types=”…”/> 语法来引用它们。例如,如果您的库依赖于流行库“lodash”的类型定义,您可以按以下方式包含引用:
/// <reference types="lodash" />
这确保了TypeScript编译器在编译代码时包括了“lodash”的类型定义。
第八步:测试和优化
一旦你定义了类型定义文件,就必须在你的代码库中进行测试。在你的TypeScript项目中导入或者引入库,并使用定义好的类型和接口。如果TypeScript编译器抛出任何错误,或者库的行为与定义的类型不匹配,则返回你的类型定义文件,并进行相应的优化。
示例1
让我们来看一个实际例子。
让我们创建一个名为 my-library 的模块,其中有一个实用函数 capitalize ,它接受一个字符串,然后返回它的大写版本。
my-library.js
function capitalize(st) {
return st.charAt(0).toUpperCase() + st.slice(1);
}
module.exports = {
capitalize: capitalize,
};
现在,我们将创建一个类型定义文件来限制在编译时使用导出的 capitalize 函数的类型检查 –
首先,创建一个名为 my-library.d.ts 的新文件,内容如下 –
declare module 'my-library' {
export function capitalize(str: string): string;
}
在上面的示例中,我们声明一个名为“my-library”的模块,并导出一个函数 capitalize ,该函数接受一个字符串参数并返回一个字符串。
现在您可以在您的TypeScript代码中安全地使用 capitalize 函数。我们现在创建一个 app.ts 文件来使用我们的 capitalize 函数 −
app.ts
/// <reference types="node" />
const { capitalize } = require("./my-library");
const result = capitalize("hello");
console.log(result); // Output: Hello
通过添加 < reference types=”node” />指令,您告诉TypeScript使用已安装的Node.js类型定义 require 函数。现在,TypeScript应该能够识别require函数。
通过提供准确的类型定义,TypeScript编译器可以验证 capitalize 函数的使用情况,防止任何潜在的类型错误。
输出
它将产生以下输出 –
Hello
结论
创建TypeScript类型定义文件(.d.ts)可以让开发者在使用外部JavaScript库和模块时发挥静态类型的优势,提高开发者的体验。通过按照逐步分析库结构、声明模块、定义类型和接口、测试和调整类型定义的过程,开发者可以确保项目具有准确和全面的类型定义。通过使用类型定义文件,TypeScript提供了更好的代码质量、早期错误检测和更好的可维护性。通过投入时间创建精确的类型定义,开发者可以充分利用TypeScript在开发流程中的好处。