如何手動補充陳年老庫(或純 JS 代碼)的 TypeScript 類型?

来源:https://www.cnblogs.com/onsummer/archive/2023/01/31/17080178.html
-Advertisement-
Play Games

這篇僅為自己工作中在 js 和 ts 交叉鬥智鬥勇的實踐中留下的經驗,不一定完全、合理,僅供參考,有錯漏難免,有則評論區指出。 前置知識 - JavaScript 的各種模塊化情況 全局模塊,在 globalThis 上可以訪問,一般是 iife 庫程式 ES 模塊 CommonJS 模塊 前置知識 ...


目錄


這篇僅為自己工作中在 js 和 ts 交叉鬥智鬥勇的實踐中留下的經驗,不一定完全、合理,僅供參考,有錯漏難免,有則評論區指出。

前置知識 - JavaScript 的各種模塊化情況

  • 全局模塊,在 globalThis 上可以訪問,一般是 iife 庫程式

  • ES 模塊

  • CommonJS 模塊

前置知識2 - 讓你寫的 d.ts 在工程中生效

  • 確保當前工程目錄中使用的 TypeScript 是 node_modules 下的開發依賴,快捷命令 Ctrl + Shift + P,選擇 TypeScript 版本即可

  • tsconfig.json 中配置 include 項,使得你寫的 d.ts 文件在 include 的路徑中即可

1. 全局模塊的定義

假設我有一個定義在 globalThis 上的庫,名叫 WebCC,它很簡單:

window.WebCC = (function(){
  const foo = () => {
    console.log('foo')    
  }
  const bar = 'bar'
  const NAME = 'WebCC'
  return {
    foo,
    bar,
    NAME
  }
})()

那麼,它應該使用 namespace 來定義:

declare namespace WebCC {
  function foo(): void
  const bar: string
  const NAME: string
}

2. ES 模塊的定義

仍以上述 WebCC 這個名字為例,但是這次是 ES 模塊:

// webcc.js
export const bar = 'bar'
export const NAME = 'WebCC'
export const foo = () => {
  console.log('foo')
}

那麼,它應該使用 module 來定義:

// webcc.d.ts
declare module 'webcc' {
  export const bar: string
  export const NAME: string
  export const foo: () => void
}

module 關鍵字後面的模塊名即 import 時的模塊名:

import { foo } from 'webcc'

2.1. 預設導出

declare module 'webcc' {
  const XXX: string
  export default XXX
}

2.2. 導出類

declare module 'webcc' {
  export class Foo {
    /** 構造器 */
    constructor()
    /** 欄位成員,類型為函數 */
    foo: () => void
    /** 欄位成員,類型為 string */
    NAME: string
    /** 函數成員 */
    bar(): void
    /** 靜態欄位成員,類型為 number */
    static VERSION: number
  }
}

2.3. 註意事項

在模塊聲明的 d.ts 文件中,想引入其他模塊的定義,不能像模塊一樣使用 import 指令,而是要使用 import()。例如,想在 parser.d.ts 中引入別人已經定義好的數據類型,來自 @types/fooFoo 類型,那麼要寫成:

declare module 'my-parser' {
  export parse(val: import('foo').Foo): string
}

這是因為一旦在代碼文件頂部寫了 import 就會被當作模塊文件,而不是類型聲明文件。這個特性來自 TS 2.9 版本。

3. CommonJS 模塊定義

CommonJS 的模塊聲明與 ES 模塊聲明大同小異,即 module.exports.foo(或簡寫 exports.foo)對應 export foomodule.exports = foo 對應 export default foo

3.1. 挨個導出

module.exports = {
  foo: function() {
    console.log('foo')  
  },
  bar: "bar"
}

類型聲明為:

declare module 'webcc' {
  export const foo: () => void
  export const bar: string
}

3.2. 預設導出

module.exports = class WebCC {
  foo() {
    console.log('foo')   
  }
}

類型聲明為:

declare module 'webcc' {
  export default class WebCC {
    foo(): void
  }
}

4. 聲明類型(TypeScript 中的 interface 或 type)和其它

4.1. type 和 interface

滿足前置知識2 的前提下,在任意 d.ts 中書寫的 interfacetype 定義均可被整個項目使用:

declare type WebCCOptions = {
  foo: string
  bar: boolean
}
declare interface WebCCResponse {
  foo: string
}

4.2. 全局變數(非 namespace)

全局變數也可以如法炮製:

declare const WebCC: {
  foo: () => void
}

4.3. 補充功能

例如,想為原生數組補充一個新的函數成員 foo,先在某些地方實現:

// somefile.js
Array.prototype.foo = function() {
  console.log('foo')
}

這個時候需要補齊這個類型:

// somefile.d.ts
declare interface Array<T> {
  foo(): void
}

有的讀者可能不知道為什麼 Array 是 interface,那是因為這個是官方的定義,我只是點了點 F12 ... 畢竟 interface 才能繼續補充定義,官方的 d.ts 更完善、強大,建議自學。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.背景知識 CRLF用來表示文本換行的方式 ,CR是回車的意思,對應 \r ;LF 是換行的意思,對應 \n Windows 換行符是 \r\n Unix 換行是 \n 如果一個將要在Linux伺服器上使用的文件,比如某個配置文件,在windows電腦打開,編輯過,那麼文件每一行末尾會多有\r 。 ...
  • MySQL中既存在redo log,又存在bin log,這是因為bin log是MySQL Server提供的一種歸檔日誌,其本身並不具備crash-safe能力。而redo log本身不具備歸檔能力,他是一種迴圈寫的日誌。 MySQL通過將這兩種日誌整合起來,並通過兩階段提交的機制,保證了數據... ...
  • 一:背景 1. 講故事 相信絕大部分用 SQLSERVER 作為底層存儲的程式員都知道 nolock 關鍵詞,即使當時不知道也會在踩過若幹阻塞坑之後果斷的加上 nolock,但這玩意有什麼註意事項呢?這就需要瞭解它的底層原理了。 二:nolock 的原理 1. sql 阻塞還原 為了方便講述,先創建 ...
  • Redis 每秒可以處理超過 10 萬次讀寫操作,是已知性能最快的 key-value 資料庫,稱得上是必須要學會的知識。 ...
  • 華為 HMS Core 音頻編輯服務(Audio Editor Kit)是華為幫助全球開發者快速構建各類應用音頻能力的服務,匯聚了華為在音樂、語音等相關音頻領域的先進技術。音頻編輯服務為開發者們提供音頻基礎編輯、AI配音、音源分離、空間渲染、變聲、多種音效等豐富的音頻處理能力,以及性能優異、簡單易用 ...
  • 一、前言 你可以使用任意文本編輯器,再結合命令行工具來開發 Flutter 應用。然而,我們推薦使用本文接下來介紹的編輯器插件以獲取更好的開發體驗。這些插件提供了代碼補全、代碼高亮、widget 輔助編輯的功能,以及為項目的運行和調試提供支持等。 推薦的開發工具有 VS Code、Android S ...
  • 隨著移動互聯網的高速發展,各家大廠的小程式百花齊放,在用戶規模及商業化方面都取得了極大的成功。微信小程式的日活超過5億,其他追趕者如:支付寶、百度、位元組跳動小程式的月活也紛紛超過3億。鑒於小程式相比App,無需下載等待,有更高的激活率,相比H5有更好的下單轉化率,汽車報價業務線藉助各平臺的優勢,大力... ...
  • 我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。 相容性問題 第三方依賴相容問題 React - 最低 v16.9,部分組件使用 hooks 重構 react升級相關文檔 Less - 最低 v3.1.0,建議升級到 ...
一周排行
    -Advertisement-
    Play Games
  • @ 先看一下導出的整體效果(如下圖),其中標註的區域都是通過後臺動態生成的: 一、先在Word中建立好表格模板 1.1、參數創建方法(Word和WPS) 1.1.1、Office中Word域的創建 1.1.1.1、選中指定的單元格 -> 點擊頭部工具欄中的”插入“ -> 選擇 ”文檔部件“ -> 選 ...
  • 在實際工作中,經常會有一些需要定時操作的業務,如:定時發郵件,定時統計信息等內容,那麼如何實現才能使得我們的項目整齊劃一呢?本文通過一些簡單的小例子,簡述在.Net6+Quartz實現定時任務的一些基本操作,及相關知識介紹,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 紙殼CMS支持將評論、留言、表單提交、訂閱等通知,通過WebHook發送到第三方平臺,比如釘釘。 創建釘釘WebHook 需要在釘釘群中創建自定義機器人,具體方法可以參考釘釘的官方文檔: 自定義機器人接入 需要註意的是,在安全設置中不要使用加簽,使用自定義關鍵字即可。在發送的消息中,只要包含這個關鍵 ...
  • 向下轉型的使用 Java的多態性: 父類指向子類的聲明 Animal animal = new Dog()//Dog()重寫了父類Animal 有了對象的多態性以後,記憶體實際上載入的是==子類==的屬性和方法,但是由於變數聲明為==父類類型==,導致編譯時只能調用父類的屬性和方法,子類特有的屬性方法 ...
  • spring源碼環境搭建 組件 版本 jdk 1.8.0_192 spring-framework 5.3.x gradle 7.5.1 idea 2022.3.3 aspectJ 1.9 可根據spring-framwork項目說明靈活選擇 一、拉取spring-framework項目 1、spr ...
  • 首先任何的商業邏輯,光流量增長,沒法變現是沒用的。 就像博客群發提效工具,得有對應的用戶,更得有對應付費用戶群體的畫像。剩下的就是靠增長,被動讓他們找到你的產品,用產品解決他們痛點,他們自然而然會付費。 下麵大致分享下從三個方向分享下: 用戶痛點 -> 真正的付費用戶群體 產品價值 PLG 增長 一 ...
  • Object類的使用 Object類 Object類中的方法可以在網上搜索得到 Object類是所有java類的父類 如果類在聲明中未使用extends關鍵字指明其父類,則預設父類為java.lang.Object類 Object類中的功能(屬性、方法)具有通用性。 屬性:無 方法:equals() ...
  • Qt 源碼分析之moveToThread 這一次,我們來看Qt中關於將一個QObject對象移動至一個線程的函數moveToThread Qt使用線程的基本方法 首先,我們簡單的介紹一下在Qt中使用多線程的幾種方法: 重寫QThread的run函數,將要在多線程執行的任務放到run函數里 /*myt ...
  • 包裝類的使用 包裝類的使用 java提供8種基本數據類型對應的包裝類,使得基本數據類型變數具有類的特征 掌握:==基本數據類型、包裝類、String==三者之間的互相轉換 自動裝箱與自動拆箱==[基本數據類型和包裝類的轉換]== JDK5.0新特性,自動裝箱與自動拆箱。 class Test{ pu ...
  • 本文已經收錄到Github倉庫,該倉庫包含電腦基礎、Java基礎、多線程、JVM、資料庫、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分散式、微服務、設計模式、架構、校招社招分享等核心知識點,歡迎star~ Github地址 大家好,我是大彬~ 今天來聊聊接 ...