如何在 TypeScript 中声明全局变量?

原文链接:Declaring Global Variables in TypeScript,2020.04.14,by Marius Schulz.

有时候,你可能想在 TypeScript 使用一些自定义全局变量。例如,在我的一些 Web 应用程序中,我需要将一些从服务器端渲染时传递过来的属性的给在浏览器中运行的 JavaScript 代码使用。为了做到这一点,通常我会在内联脚本中定义一个名为 __INITIAL_DATA__ 的全局变量,并将一个 JSON 序列化对象赋值给它:

html 复制代码
<script>
  window.__INITIAL_DATA__ = {
    userID: "536891193569405430",
  };
</script>

现在,如果我尝试在一个 TypeScript 文件中访问 window.__INITIAL_DATA__ 时,编译器就会产生一个类型错误,因为它找不到 __INITIAL_DATA__ 属性的定义。

typescript 复制代码
// Property '__INITIAL_DATA__' does not exist
// on type 'Window & typeof globalThis'
const initialData = window.__INITIAL_DATA__;

接下来,我将向你展示几种不同的方法,让 TypeScript 知道 window.__INITIAL_DATA__ 属性的存在,并消除类型错误。

使用类型断言

消除类型错误的最快方法是在类型断言中使用 any 类型。我们可以将 window 对象视为任意类型,以便访问其 __INITIAL_DATA__ 属性:

typescript 复制代码
const initialData = (window as any).__INITIAL_DATA__;

这个解决方案有效,我们不再遇到类型错误。如果你需要一种临时的方式来访问 TypeScript 不知道的 window 对象上的属性,这是一个实用的方法。

(window as any).__INITIAL_DATA__ 表达式是任意类型,因此 initialData 也是任意类型。我们可以进一步使用另一种类型断言来给 initialData 变量指定更具体的类型:

typescript 复制代码
type InitialData = {
  userID: string;
};

const initialData = (window as any).__INITIAL_DATA__ as InitialData;

现在,我们可以以类型安全的方式访问 initialData.userID

typescript 复制代码
const userID = initialData.userID; // string 类型

请记住,这并不保证 window.__INITIAL_DATA__ 在运行时会被正确设置。类型检查器相信我们,并且我们的工作是确保将一个符合预期形状的对象赋值给 window.__INITIAL_DATA__

声明一个全局变量

另一种方法是使用 declare var 语法声明一个全局变量。这样,我们可以让 TypeScript 找到这个具有给定名称和类型的全局变量:

typescript 复制代码
declare var __INITIAL_DATA__: InitialData;

我们现在可以直接访问 __INITIAL_DATA__ 变量了......

typescript 复制代码
const initialData = __INITIAL_DATA__;

......或通过 window 对象获取:

typescript 复制代码
const initialData = window.__INITIAL_DATA__;

有一点要注意的是,在ECMAScript 模块内部通过 declare var 声明的变量是是无法通过 window.__INITIAL_DATA__ 形式访问的,会收到类型错误。而所谓 ECMAScript 模块就是包含顶级 importexport 声明的那些文件。

你可以使用 declare global { ... } 语法在全局作用域中声明一个全局变量,以便能够在 JavaScript 模块内部或外部文件通过 window.__INITIAL_DATA____INITIAL_DATA__ 两种形式访问。

typescript 复制代码
export function someExportedFunction() {
  // ...
}

declare global {
  var __INITIAL_DATA__: InitialData;
}

const initialData = window.__INITIAL_DATA__;

如果你需要在多个文件或模块中访问 window.__INITIAL_DATA__,那么在项目中创建一个 globals.d.ts 文件可能是个好主意。在这个文件中,你可以声明所有将要使用的全局变量:

typescript 复制代码
declare var __INITIAL_DATA__: InitialData;

增强 Window 接口

最后,你可以使用 TypeScript 的接口声明合并来告诉编译器在 Window 类型上有一个名为 __INITIAL_DATA__ 的属性。为了做到这一点,你需要定义一个名为 Window 的接口,设置一个名为 __INITIAL_DATA__ 的属性:

typescript 复制代码
interface Window {
  __INITIAL_DATA__: InitialData;
}

TypeScript 将会上面的这个接口定义和 lib.dom.d.ts 中定义的 Window 接口合并,从而得到一个单一的 Window 类型。这样一来,下面的赋值就不再产生类型错误了:

typescript 复制代码
const initialData = window.__INITIAL_DATA__;

请注意,这种方法同样 ECMAScript 模块中不起作用。为了使 window.__INITIAL_DATA__ 表达式能够正确进行类型检查,需要再次使用 declare global { ... } 语法:

typescript 复制代码
export function someExportedFunction() {
  // ...
}

declare global {
  interface Window {
    __INITIAL_DATA__: InitialData;
  }
}

const initialData = window.__INITIAL_DATA__;
相关推荐
故事与他64511 分钟前
XSS_and_Mysql_file靶场攻略
前端·学习方法·xss
莫的感情1 小时前
下载按钮点击一次却下载两个文件问题
前端
一个很帅的帅哥1 小时前
JavaScript事件循环
开发语言·前端·javascript
小宁爱Python1 小时前
Django Web 开发系列(二):视图进阶、快捷函数与请求响应处理
前端·django·sqlite
fox_1 小时前
深入理解React中的不可变性:原理、价值与实践
前端·react.js
Github项目推荐1 小时前
你的错误处理一团糟-是时候修复它了-🛠️
前端·后端
Code小翊1 小时前
C语言bsearch的使用
java·c语言·前端
云枫晖1 小时前
Webapck系列-初识Webpack
前端·javascript
慧一居士1 小时前
HTML5 功能介绍,使用场景,对应功能点完整使用示例
前端
海在掘金611271 小时前
告别“undefined is not a function”:TS如何让你的函数调用更安心
前端