大家好,今天要來聊聊npm套件
TypeScript之所以好用,是因為它能在寫程式的當下就告訴你「這個函式要傳什麼參數」、「回傳值是什麼型別」。
但問題來了——npm上有許多套件是用JavaScript撰寫,或沒有隨套件提供TypeScript型別宣告。當 TypeScript 使用這些套件時,就可能無法得知它們的型別資訊。
這時候,套件的型別資訊會有三種可能來源:
有些套件會直接在套件裡提供型別宣告檔,透過package.json的types或typings欄位告訴 TypeScript型別宣告檔的位置。這種套件在 package.json 裡通常會有一個欄位:
{
"name": "some-package",
"main": "index.js",
"types": "index.d.ts"
}
備註:有些舊套件用的欄位名稱是 typings
如果套件已經正確提供型別宣告,通常不需要另外安裝@types,直接import就能取得型別資訊。
如果套件本身沒附型別,TypeScript社群維護了一個超巨大的專案,叫做:Definitely Typed,這是一個GitHub上的開源專案,專門收集別人寫好的型別宣告檔,涵蓋了許多第三方的JS套件(像早期的 lodash、express 等)。
這些型別會被打包發布到npm上,命名規則統一是:
@types/套件名稱
所以如果在用某個套件時遇到型別缺失的錯誤,可以先去npm上查查看有沒有對應的@types 套件,通常是這樣安裝:
npm install -D @types/xxx
-D?因為@types提供的是TypeScript在開發與型別檢查時需要的宣告檔,程式實際執行時不需要載入這些型別,所以通常會安裝在devDependencies。
小提醒:
@types/xxx是社群維護的,版本可能跟原套件的功能有落差(尤其是套件更新很快,但型別檔沒跟上時)。
這時候我們可以自己寫一份型別宣告檔,副檔名就是熟悉的:.d.ts,.d.ts 是「declaration file(宣告檔)」的縮寫。
.d.ts特色是:
tsc --declaration 幫自己的專案產生)假設開發者在用一個完全沒有型別的套件my-legacy-lib,可以自己建立一個 my-legacy-lib.d.ts:
declare module "my-legacy-lib" {
export function doSomething(input: string): number;
}
這樣 TypeScript 看到這個模組時,就會參考你寫的宣告,不會再報錯了。
declare是什麼?上面範例中出現的 declare,是 TypeScript 一個很關鍵但常被忽略的關鍵字。
declare 的作用是告訴TypeScript這個東西已經存在了,不用管它是怎麼實作出來的,只要知道它的型別長怎樣就好。
常見的使用情境:
1. 宣告全域變數(例如透過 <script> 標籤引入的外部函式庫,全域會有一個變數)
declare const $: any; //這裡使用any只是為了示範declare,實際專案會希望提供更精確的型別
2. 宣告模組(就是上面補型別的例子)
declare module "some-untyped-package" {
export function foo(): void;
}
3. 搭配 .d.ts 檔案一起使用,讓TypeScript知道某個外部資源的型別存在,但實際內容不用它來檢查。
今天淺談了關於npm套件的小知識,明天來講講在TS中常見的錯誤和debug,今天的內容就到這邊啦!