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)
也就是說我們將一個字串賦值給了一個數字型別的變數是有問題的,這個時候我們未執行程式,但是編輯器已經幫我們分析出了程式碼可能存在的問題,這時候我們執行程式碼,是沒有報錯的。
因為這個型別檢測只是讓我們按照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;
可以在第一行上使用
object
或Object
。
實驗要求
經測試,在 VSCode
和IDEA
下可以直接使用ts-check
的型別檢測,sublime
等編輯器不可以,應該是要下載對應的外掛才可以。
寫在最後
對於老專案,使用 // @ts-check
和 JSDoc
來來享受TypeScript型別系統的好處是最簡單、學習成本最低的方法。
而對於新專案,則更加推薦直接使用 TypeScript 來進行程式碼編寫,並且各大框架裡面都是用的TypeScript進行的程式碼編寫,在可期的未來,TypeScript將會越來越受歡迎。