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”。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章