JS的靜態類型檢測,有內味兒了

我們知道 TypeScript 2.3 以後的版本支持使用--checkJs.js文件進行類型檢查和錯誤提示。 但是由於 JavaScript 是弱類型語言,在編寫代碼的時候,是無法檢測變量的類型的。

因此每次運行代碼類型報錯的時候,我心中都會冒出來一個強烈的願望:要是 JavaScript是強類型的多好!

好消息是,JSDoc 的 @ts-check,可以現實這個願望。

立即上手

如果能有機會使用 TypeScript 那當然是最好,但是往往開發的老項目在早期都是 JavaScript 完成的,如果都遷移到 TypeScript 版本工作量是龐大的,而且不可避免出現許多bug問題,那麼有沒有一種方式可以無痛的在使用JavaScript的同時享受到TypeScript的類型檢查呢?

答案就是 // @ts-check,在 js 文件的頭部引入這樣一行註釋,然後配合JSDoc就可以在JavaScript代碼中使用 TypeScript的類型檢查了。

舉個例子,在下圖中我們首先聲明瞭一個變量 a,然後把數字 1 賦給了它,接着又把字符串 '1' 賦給了它,看起來好像沒有什麼問題,而且運行起來也不會報錯。

let a = 1;
a = 'a';

然後我們加上 // @ts-check 試試:

// @ts-check

/**
 * @type {Number}
 */
let a = 1;
a = '1';

神奇的一幕出現了,在變量a賦值的下面,出現了紅色波浪線,鼠標放上去提示:

let a: number
@type — {Number}
不能將類型“"1"”分配給類型“number”。ts(2322)

1

也就是說我們將一個字符串賦值給了一個數字類型的變量是有問題的,這個時候我們未運行程序,但是編輯器已經幫我們分析出了代碼可能存在的問題,這時候我們運行代碼,是沒有報錯的。

因爲這個類型檢測只是讓我們按照TypeScript的強類型語言檢測類型問題,但是我們依然是JavaScript代碼依然會按照JavaScript的代碼邏輯運行,如是TypeScript代碼的話,這裏運行就會報錯。

JSDoc 類型標記

既然ts-check這麼好用,我們來看看 JSDoc 類型的註釋支持哪些類型的檢測。

根據官方文檔,JSDoc現在支持下面幾個類型檢測:

  • @type
  • @param (or @arg or @argument)
  • @returns (or @return)
  • @typedef
  • @callback
  • @template
  • @class (or @constructor)
  • @this
  • @extends (or @augments)
  • @enum

下面我們選擇常用的標記進行說明,更多更詳細的標記可以參考官方文檔

@type

描述:用來聲明變量的類型。

/** 
 *  - string類型
 * @type {string}
 */
let a1;

/** 
 *  - windows對象類型
 * @type {Window}
 */
let a2;
 
/** 
 * - string或者boolean類型
 * @type {string | boolean}
 */
let sb;


// -------- 多種方式指定數組類型--------
/** @type {number[]} */
var ns;
/** @type {Array.<number>} */
var nds;
/** @type {Array<number>} */
var nas;

// ---- 還可以指定對象字面量類型。 例如,一個帶有a(字符串)和b(數字)屬性的對象---
/** @type {{ a: string, b: number }} */
var var9;

@param和@returns

描述:@param語法和@type相同,但增加了一個參數名。

/**
 * 聲明函數參數類型
 * @param {string}  p1 - p1 是 string 類型參數
 * @param {string=} p2 - p2 是可選的 string 類型參數
 * @param {string} [p3] - 另外一種可選參數寫法
 * @param {string} [p4="test"] - p4 是可選的 string 類型參數(默認值爲 "test")
 * @return {string} - 函數返回值是 string 類型
 */
function fn3(p1, p2, p3, p4){
  // TODO
}


/**
 * 用 “return” 說明函數的返回值類型
 * @return {number}
 */
function fn1() {}

/**
 * 可以像使用 "@return" 一樣使用 "@returns"
 * @returns {{a: string, b: number}}
 */
function fn2() {}

@typedef

描述:@typedef 可以用來聲明覆雜類型,和@param類似的語法。

/**
 * 用 "@typedef" 自定義複雜類型
 * @typedef {Object} SpecialType - 創建一個新的類型 'SpecialType'
 * @property {string} prop1 - SpecialType 屬性 prop1 是 string 類型
 * @property {number} prop2 - SpecialType 屬性 prop2 是 number 類型
 * @property {number=} prop3 - SpecialType 屬性 prop3 是可選的 number 類型
 * @prop {number} [prop4] - SpecialType 屬性 prop4 是可選的 number 類型
 * @prop {number} [prop5=42] - SpecialType 屬性 prop5 是可選的 number 類型(默認值 42))
 */
/** @type {SpecialType} */
let specialTypeObject;

可以在第一行上使用objectObject

實驗要求

經測試,在 VSCodeIDEA下可以直接使用ts-check 的類型檢測,sublime等編輯器不可以,應該是要下載對應的插件纔可以。

寫在最後

對於老項目,使用 // @ts-checkJSDoc 來來享受TypeScript類型系統的好處是最簡單、學習成本最低的方法。

而對於新項目,則更加推薦直接使用 TypeScript 來進行代碼編寫,並且各大框架裏面都是用的TypeScript進行的代碼編寫,在可期的未來,TypeScript將會越來越受歡迎。

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