使用 JSDoc 標註類型

JavaScript 採用動態類型,在編譯期不對類型進行檢查,等真正執行的時候由運行時來判斷類型是否出現錯誤,這種特性有點像彙編裏的計算同樣,類型很弱,不一樣類型老是顯式、隱式地轉換。javascript

在一個普通的 Todo Demo 裏類型或許沒有那麼重要,而當項目變得龐大起來的時候,裏邊有不少不一樣的邏輯,當項目由另一我的接手的時候,閱讀就很麻煩,由於老是要查看代碼上下文的各個變量的類型(自定義類型或者原生類型),通常來講,在前端 console.log 一下就能夠看到了,但也只是一個臨時的辦法,治標不治本。css

固然,強類型的 JavaScript 已經很成熟了,那就是 TypeScript,但並非全部項目一開始就是 TS 寫的,也有純 JS 的項目,那麼在這些項目裏如何維護好類型?html

答案是在 VSCode 下使用 JSDoc;VSCode 會盡最大努力推導出類型出來的。前端

什麼是 JSDoc

JSDoc 其實就是代碼註釋,在這種註釋裏能夠標明 JavaScript 裏值的類型,以及對代碼的註釋,一般能夠在代碼裏看到以 @ 符開頭的標註,那就是 JSDoc 了。如下是一個簡單的例子java

/** * 加法 * @param { Number } x * @param { Number } y * @returns { Number } */
function add(x, y) {
    return x + y; 
}
複製代碼

上面 @param, @returns 就說明了參數 x y 以及函數的返回值的類型。git

參考 VSCode - type-checking 能夠顯式的打開 JS 的類型檢查:github

打開類型檢查能夠看到傳入其餘類型的參數的時候會報錯

打開類型檢查能夠看到傳入其餘類型的參數的時候會報錯,而填入了正確的類型的值以後,VSCode 就能知道 z 是什麼類型的了(由於 x, y 均爲數字,x + y 也理所固然的是數字)express

也就能實現代碼補全提示了:數組

代碼補全

標註代碼裏的基本類型

@param 後能夠接 String Number Array Object 等等。 如:函數

/** * * @param { Array<Number> } numbers * @param { String[] } names */
function test(numbers, names) {
    names.forEach(name => {
        // ... 
    })
}
複製代碼

上面的 String[] 的寫法其實與 Array<String> 是同樣的,表示了一個元素爲字符串的數組,並且 VSCode 一樣能代碼自動補全 forEach 方法以及 name 的方法來(String.pototype)。

而下面的例子表示一個自定義的對象:

/** * say hello * @param { { name: String } } person */
function sayHello(person) {
    console.log(person.name); 
}
複製代碼

@param 標明函數的參數的類型;@returns 標明函數的類型。

標註自定義類型

其實在上面的例子裏就有了關於自定義類型的說明(對象的那個),但上述的那個例子是針對字面量的聲明,如今介紹一下 VSCode 對 JavaScript 類的處理。

class Person {
    /** * Person * @param { String } name */
    constructor(name) {
        this.name = name; 
    }

    /** * @returns { Person } */
    sayHello() {
        console.log('Hello, i am', this.name); 

        return this; 
    }

    /** * @param { Person } friend * @returns { Person } */
    playWith(friend) {
        this.sayHello(); 
        console.log('and i will play with', friend.name); 

        return this; 
    }
}

複製代碼

在這裏聲明瞭 Person 類,上面有方法 sayHello 還有一個 name 屬性。在 VSCode 看來,這也是一種類型,能夠做爲 @param 的參數使用(上例的 playWith 函數)

順便一提,JSDoc 裏的類型標註的語法主要來自於 Google Clojure Compile 裏的類型表達式。

泛型(有限制的)

JSDoc 一樣提供了必定能力的 泛型,但這種泛型限制很大,跟真正的泛型差的比較遠。

回到剛剛的例子 add(x, y) 若是 x y 限定死了數字,那字符串類型的 x y 的相加是否還須要從新編寫一次 add 呢?其實不用,可使用 @template 的方式來完成。

/** * 加法 * @template T * @param { T } x * @param { T } y * @returns { T } */
function add(x, y) {
    return x + y; 
}
複製代碼

此處引入了 T,能夠這樣理解這段 JSDoc:

  1. xy 的類型都是 T,說明它們的類型是同樣的,返回值也同樣。
  2. 若沒有 @template 來聲明 T,那 VSCode 會認爲它是構造函數 T 的類型,此處的 @template 聲明是說明 T 是「泛型」,它是一種特殊的變量,只用於表示類型而不是值

在使用了 @template 以後:

這說明,d 和 z 的類型須要經過 VSCode 理解了 addJSDoc 以後才能推導出來,而 T 彷佛是一個 變量,在上面兩種狀況下分別爲 stringnumber

.d.ts

還有一種類型標註的方法即便用 *.d.ts 文件,一般普通的 JavsScript 庫是不帶類型標註的,這樣會不兼容 TypeScript 裏的類型檢查,所以須要引入 d.ts 用於描述 js 庫的類型讓 ts 可以使用。

固然,VSCode 能夠讀取它,並方便開發。編寫 test.js:

/** * @param { Person } p */
function test(p) {
    
}
複製代碼

而後編寫 Person 的類型描述 test.d.ts

declare interface Person {
    name: string, 
    age?: number, 
    sayHello: () => Person, 
    playWith: (friend: Person) => Person
}
複製代碼

注:age 的問號表明年齡無關緊要。

而後 VSCode 會找到 *.d.ts 文件並讀取,獲得類型信息:

d.ts

參考連接

http://www.css88.com/doc/jsdoc/about-block-inline-tags.html https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler#type-expressions https://code.visualstudio.com/Docs/languages/javascript#_type-checking https://zh.wikipedia.org/wiki/JavaScript

相關文章
相關標籤/搜索