iT邦幫忙

2026 iThome 鐵人賽

DAY 25
0

大家好,今天要來聊聊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特色是:

  • 只寫型別,不包含任何實際的程式邏輯
  • 不會被編譯成JS,純粹是給TypeScript編譯器參考用的說明書
  • 可以自己手寫,也可能是由工具自動產生(例如用 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,今天的內容就到這邊啦!


上一篇
[Day-24]Async與Await
下一篇
[Day-26]TypeScript常見錯誤與Debug
系列文
從零開始學習TypeScript:菜鳥的入門介紹與概覽 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言