使用 polyfill 时的安全打字稿编译

Safe typescript compilation when polyfills are used

假设我有一个包含两个打字稿文件的项目:

我的tsconfig.json:

{
    "target": "ES5",            // old browser support is required
    "lib": ["dom", "es5"],      // 
    "types": []                 // 
}

我将 types 设置留空,因为我不想从任何第三方包中获取类型(例如 @types/node typings 作为 webpack-dev-server 包的依赖项安装;详情为 )

现在我决定使用一些新的 JS 功能并将以下行添加到 a.ts 文件:

let clone = Object.assign({}, {a:1});

幸运的是,编译器足够聪明,可以通过以下警告警告我:

a.ts:1:20 - error TS2339: Property 'assign' does not exist on type 'ObjectConstructor'.

所以我必须添加一个 polyfill(例如 CORE-JS package)并向 a.ts:

添加一个导入语句
import 'core-js/modules/es.object.assign'
let clone = Object.assign({}, {a:1});

但是 typescript 编译器仍然不满意,因为它没有 typings 用于我新填充的 assign 方法。我尝试安装 @types/core-js 包并将其名称添加到我的 tsconfig.json 文件中,但没有成功,所以我创建了自己的类型定义文件 object.d.ts:

interface ObjectConstructor {
    assign(target: any, ...sources: any[]): any;
}

一切都开始工作了。万岁!

然后,我添加了另一个新功能,但这次是在 b.ts 文件中。

import 'core-js/modules/es.array.from'
console.log(Array.from('foo'));

我还为新方法添加了类型定义(文件array.d.ts):

interface ArrayConstructor {
    from<T>(arrayLike: ArrayLike<T>): T[];
}

现在,由于我的两个打字文件都可以全局访问,我可以在 a.ts[=72= 中使用 Array.from ],以及 Object.assign in b.ts,这是个问题。除非我添加

import 'core-js/modules/es.object.assign'

b.ts,代码在旧浏览器中无法运行,编译器也不会告诉我。

所以,这是我的问题:

  1. 是否可以使用@types/core-js 中的类型定义并逐一公开类型(因为我正在为它们添加 polyfill)?
  2. 是否可以让我自己的类型定义对特定文件可见(不是全局可见),这样我就可以控制每个文件中填充的内容?

PS:我不会捆绑我的两个文件,因为它们必须分开发送。将 polyfill 导入提取到单独的模块中,然后将导入添加到每个文件中的该模块对我来说不是一个理想的选择,因为它可能会创建对我的文件中未使用的 polyfill 的引用,我希望结果文件尽可能小可能。

您正在使用的这种特殊形式的导入语句

import 'core-js/modules/es.object.assign'

被称为 ,是有原因的。此语句对导入出现的模块范围没有任何影响,如果存在,效果是全局的并且不明显,除非您检查导入模块中的代码实际做了什么。

这些 particular polyfills add static methods to global ObjectArray 构造函数。

因此,您对这些 polyfill 的类型定义似乎可以正常工作,至少如果 a.jsb.js 将 运行 在相同的执行上下文中并共享相同的全局对象。

然后,无论您在哪个模块中导入 polyfill,它都会修改在所有模块中可用的共享全局对象,但有一个例外 - 当您在模块范围内(不在任何函数内)有语句时加载模块时立即执行。对于这些语句,polyfill 的可用性取决于模块加载顺序,但应尽可能避免任何依赖于模块加载顺序的内容。

Is it possible to make my own type definitions visible to a particular files (not globally visible), so I'll have control over what is polyfilled in each file?

仅当每个文件将在其自己的执行上下文中执行时才需要这样做,例如,一个文件在网页中,而另一个文件在服务工作者代码中。然后每个文件中的代码实际上引用了不同的全局对象,但是 TypeScript 没有足够的方法来表示当文件一起编译时 - 在编译时(对于类型声明),只有一个全局范围。在这种情况下,您必须使用单独的 tsconfig.json 文件在其自己单独的项目中编译每个文件,并仅在需要的地方包含 Array.fromObject.assign 的类型。