在 TypeScript 中扩展 Node.js Global (globalThis) 对象
要在 TypeScript 中扩展 Global (globalThis) 对象,需要创建一个 .d.ts 文件并使用 declare global{}
来扩展具有必要属性或方法的类型的全局对象。 TypeScript 在查找常规 .ts 文件的相同位置查找 .d.ts 文件。
在 src 目录中,创建一个包含以下 index.d.ts 文件的 types 目录:
index.d.ts
/* eslint-disable no-var */ interface Employee { name: string; age: number; } declare global { var myObj: Employee; function sum(a: number, b: number): number; } export {};
上面的示例显示了如何使用名为 myObj 的属性扩展全局 (globalThis) 对象,该属性是 Employee 类型的对象和 sum 函数。
注意
,这在我们的用例中会有所不同,因此请确保调整属性名称和类型。
确保使用 var
关键字为我们打算在其他文件中设置和使用的属性添加类型。
我们需要在 global
对象上添加要访问的所有属性的名称和类型。
例如,如果我们不知道特定属性的类型并想关闭类型检查,请将其设置为 any
。
/* eslint-disable no-var */
declare global {
var myObj: any; // 👈️ disables type checking for property
function sum(a: number, b: number): number;
}
export {};
现在,我们可以在 global
对象上设置和访问指定的属性,而不会出现任何错误。
global.myObj = {
name: 'James',
age: 30,
};
console.log(global.myObj.name); // 👉️ "James"
console.log(global.myObj.age); // 👉️ 30
global.sum = (a: number, b: number) => {
return a + b;
};
console.log(global.sum(50, 50)); // 👉️ 100
注意
,如果我们使用的是 ts-node,在我们的终端可能仍会出现错误。
问题在于 ts-node 无法识别本地声明文件。
要解决这个问题,请在 ts-node 命令中使用 --files 标志,因此我们应该运行下面的命令
$ ts-node --files ./src/index.ts
我们将 nodemon 与 ts-node 一起使用,这是我的 nodemon.json 文件的内容。
{
"watch": ["src"],
"ext": ".ts,.js",
"ignore": [],
"exec": "ts-node --files ./src/index.ts"
}
添加 --files
标志后(仅在使用 ts-node 时才需要),重新启动您的服务器,您应该一切顺利。
注意,这使得 sum
函数和 myObj 属性可以直接(全局)和在全局对象上访问。
global.myObj = {
name: 'James',
age: 30,
};
global.sum = (a: number, b: number) => {
return a + b;
};
console.log(global.myObj); // 👉️ {name: 'James', age: 30}
console.log(global.sum(50, 50)); // 👉️ 100
console.log(myObj); // 👉️ {name: 'James', age: 30}
console.log(sum(50, 50)); // 👉️ 100
如果我们尝试访问未在 declare global{}
对象中显式添加的属性,则会收到错误消息:
// ⛔️ Error: Element implicitly has an 'any'
// type because type 'typeof globalThis'
// has no index signature.ts(7017)
global.hello = 'world';
如果你的 IDE 中仍然出现错误,请尝试将类型目录的路径添加到 tsconfig.json
文件中。
{
"compilerOptions": {
// ... rest
"typeRoots": ["./node_modules/@types", "./src/types"]
}
}
我们在 index.d.ts 文件中使用 export {}
行将其标记为外部模块。 模块是包含至少 1 个导入或导出语句的文件。 我们必须这样做才能扩大 global
范围。
注意
,我们必须根据自己的用例更改提供的 index.d.ts 文件的内容。
我们应该在 global
对象上添加我们打算访问的所有属性的名称(和类型)。
/* eslint-disable no-var */
declare global {
var myObj: any; // 👈️ 禁用属性的类型检查
function sum(a: number, b: number): number;
}
export {};
提供的文件只是添加了 myObj 类型为 any 的属性,这很可能不是我们需要的。
TypeScript 在查找常规 .ts 文件的相同位置查找 .d.ts 文件,这取决于 tsconfig.json 文件中的包含和排除设置。
TypeScript 会将我们在全局对象上声明的类型与原始类型合并,因此我们将能够从两个声明中访问属性和方法。