TypeScript -聲明文件

遇到問題:

開發超五card過程中,使用TypeScript寫代碼,因爲項目中需要引入moment,來處理日期格式問題。像往常一樣下載引入:

tnpm i moment --save
import * as moment from 'moment';

引入後發現有紅色波浪線,但是頁面並沒有報錯

image.png

 

前端第三方庫大多都是非 TypeScript 庫,基本上都是使用 JS 編寫的,在 TS 中使用非 TS 編寫的第三方庫,需要有個 xx.d.ts 聲明文件。引入聲明文件後,就能獲得對應的代碼補全、接口提示等功能。這裏的報錯就是缺少聲明文件引起的。

 

解決方案:

 

一,npm包

首先,查找下社區有沒有引入模塊的聲明文件。通過 https://www.npmjs.com/ 網址進行搜索。一般依賴的格式爲 @types/xxxx 。例如:@types/jQuery,@types/lodash等等。如果可以搜索到,就直接安裝。npm install @types/lodash --save-dev。一般情況下會自動查找node?_modules/@types中的聲明文件。

二,某些模塊自帶聲明文件

有些模自帶聲明文件。判斷依據是 package.json 中有 types 字段,或者有一個 index.d.ts 聲明文件。這種模式不需要額外安裝其他包,是最爲推薦的,所以以後我們自己創建 npm 包的時候,最好也將聲明文件與 npm 包綁定在一起。

 

例如:和 moment 等等。node_modules中找到moment模塊,打開可以看到自帶了聲明文件,但是還是會有報錯的問題。這裏可能是momet的聲明文件有點問題。

image.png

對於moment的聲明文件,我的解決方法是這樣的:

npm i typings  項目中會多個typings文件夾
typings install dt~moment --global --save

image.png

剛剛下載的moment的聲明文件被放在typings下面

index.d.ts文件內容:


 

這是一種引入.d.ts文件的方式。

修改tsconfig.json配置文件,include屬性中新增一個typings元素,這樣如果node_modules中找不到聲明文件,就會去typings中查找。

{
  "compilerOptions": {
    "baseUrl": ".",
    "target": "es6",
    "noImplicitThis": true,
    "noImplicitUseStrict": true,
    "types": ["mini-types"]
  },
  "include": [
    "src/**/*",
    "typings", // 新增
  ]
}

這樣報錯就沒有了,鼠標放在引入的moment上面,可以很清楚的看到提示信息:

image.png

三,自己寫聲明文件

如果以上兩種方式都不能解決問題,就需要自己寫聲明文件了。

比如在項目中引入一個第三方工具庫:

import startApp from '@alipay/merchant-mini-utils/startApp';

這個工具沒有自己的聲明文件。

可以在typings/index.d.ts文件中寫自己的聲明語句,擴展全局模塊:

declare module "@alipay/merchant-mini-utils/startApp" {
  type Params = {
    appId: string;
    startMultApp: string;
    redirect: boolean;
    success: () => void;
    fail: () => void
  };
  export default function startApp(url: string, params?: Params): void
}

在文件引入的地方可以看到提示信息,一眼就知道函數的使用方法,需要傳遞什麼參數。

image.png

這裏留有一個問題,感覺這樣寫不太對,未完待續。。。。

聲明文件的書寫規範

聲明文件的新語法有:

一 聲明全局變量

  • 文件內容定義了一個變量:
var a = 10;

引入方式:

<script src="./index.js"></script>

引入之後,變量a便可以全局使用,這個時候就需要在inde.d.ts文件中聲明一個全局變量:

declare var a:number;

 

這樣就可以在ts文件直接使用這個全局變量了。

二 聲明全局函數和帶有子屬性的全局對象

  • 文件內容定義了一個函數,函數也是對象,帶有自己的靜態屬性:
function globalFunc(params){
    console.log(params);
};
globalFunc.version = "v1.0.0";
globalFunc.dosomething = function(){
    console.log("I am globalFunc  dosomething");
};
<script src="./globalFunc.js"></script>

聲明文件:

declare function globalFunc(params:globalFunc.params):void
//類型兼容性
declare namespace globalFunc{
    const version : string;
    interface params{
        [key:string]:any
    }
    function dosomething():void;
}

注意,在聲明文件中聲明的類型,接口都會是全局的,儘量放在局部環境中去聲明。

declare function 聲明全局函數

declare namespace 聲明(含有子屬性的)全局對象

三 擴展全局變量

上面函數文件引入html後,會成爲一個全局的函數。如果我在index.ts文件中想要對這個全局函數進行擴展:

globalFunc.add = ()=>{};
//報錯如下
//Property 'add' does not exist on type 'typeof globalFunc'.

就需要增加聲明:

declare global {
    namespace globalFunc{
        function add() :void
    }
}
globalFunc.add = ()=>{};
Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.
全局作用域的擴展只能直接嵌套在外部模塊或環境模塊聲明中

可以理解爲 declare global 直接作用在模塊中,也就是必須出現 import 或者 export 這些文件裏面,這個文件纔不會被當成一個全局的 TS 腳本,而是模塊。所以,我們可以導出一個空對象,用來告訴編譯器這是一個模塊的聲明文件。

// declare global 擴展全局變量
export {}
declare global {
    namespace globalFunc{
        function add() :void
    }
}
globalFunc.add = ()=>{};
console.log(globalFunc.add());

通過 declare global 可以擴展全局變量。

四:擴展全局模塊

項目中引入了moment模塊,通過這種方式引入:import moment from "moment"

如果想對moment對象擴展一個方法:

moment.getDate = function(){
    const date = new Date();
    return Number(date);
};

就需要增加聲明文件:

declare module "moment" {
    export function getDate():number;
}

通過 declare module 可以直接擴展第三方模塊。

 

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