TS2669: Augmentations for the global scope can only be directly nested in external modules...的解决方案

看了网上不少资料,大多以讹传讹,完全不能用;因此查阅文档解决了之后记录一下。

问题的场景是这样的,做一个Vue + TS的项目,需要引入一些UMD库(需要在HTML中通过<script>标签引入)。以高德地图为例,它的文档是这样的:

在页面添加 JS API 的入口脚本标签,并将其中「您申请的key值」替换为您刚刚申请的 key;

<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值"></script> 

这种库的问题在于,相当于全局注入(挂载在window上),没有类型提示,无法在TS中使用。所以我就想着写一个声明文件来进行扩展。所以按照网上的说法,我就写了这样的代码:

// shims-global.d.ts
declare global {
  interface AMap {
    convertFrom: any;
  }

  const AMap: AMap

  interface Window {
    AMap: AMap;
  }
}

不要在意这个any,只是为了先让项目跑起来而已……

但是到了这里,就遇到了标题里的那个报错:TS2669: Augmentations for the global scope can only be directly nested in external modules or ambient module declarations。从字面意思来看,只能在外部模块或者环境模块的声明中对全局作用域进行扩展。但是这是啥意思呢?且待我慢慢道来。

事实上这个涉及到TS的模块机制。TS的文档是这么说的:

In TypeScript, just as in ECMAScript 2015, any file containing a top-level import or export is considered a module. Conversely, a file without any top-level import or export declarations is treated as a script whose contents are available in the global scope (and therefore to modules as well).

意思是,如果最上面不是import或者export,这个文件会被当成一个全局的TS脚本,而不是模块。所以,之前的写法中,最上面只有一个declare,会被编译器当成是一个脚本。而在TS中,能够进行类型扩展的只有interface、namespace和module,脚本是不能进行类型扩展的,所以就会报错。

解决方法也非常简单,让它变成一个模块就行了。可以在上面加一些无意义的import,或者加个export,都行。比如:

// shims-global.d.ts
export {}
// 或者也可以这么写,随便import个什么东西 
// import Vue from 'vue'

declare global {
  interface AMap {
    convertFrom: any;
  }

  const AMap: AMap

  interface Window {
    AMap: AMap;
  }
}

如果按照Stack Overflow上caseyWebb的说法,叫“we must force tsc to interpret this file as a module”。

发布了110 篇原创文章 · 获赞 132 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/HermitSun/article/details/104104762