Skip to main content

JSDoc Style Guide

JSDoc 標註的重要性

對函數和複雜 object 進行 JSDoc 標註,不僅增加了程式碼的可讀性,也提升了開發效率和協同作業的流暢度

  • Helper Function

    • 提升了解速度 : 透過 JSDoc,開發者可以快速得知 function 的功用、input 和 output 的格式,大大節省了解程式碼的時間
    • 增進開發效率:具備 IDE 的自動提示功能,有助於減少錯誤,並使開發流程更為暢順
  • Redux Reducer

    • 清晰展示用途和格式 : JSDoc 的標註讓 reviewer 快速掌握 reducer 的用途和 state 的格式,使瞭解整個架構變得容易
    • 減輕審查工作量 : 有助於減少 code review 的負擔,讓 review 過程更高效
    • 確保資料結構的準確性:能夠確認 API response data 的資料結構,提升資料處理的精確度
  • 強化團隊協作

    • 良好的開發體驗 : 除了自己開發時能獲得更流暢的開發體驗外,JSDoc 也讓其他夥伴在碰到你的程式碼時能迅速上手
    • 促進 code review : 有了清晰的標註,code review 的過程也變得更為輕鬆和有效,有助於提高團隊的整體生產力

JSDoc 的使用不僅使個人開發變得更為便捷,也促進了團隊間的協作和溝通

Helper Function 需加上 JSDoc 註解

新增於 /src/helpers/ 底下的 helper function 必須撰寫 JSDoc 註解,除了讓其他開發者更了解參數的格式,也能獲得更好的 IDE 提示,並適時添加其他敘述與範例,如 @exmaple

/**
* 接收 key 和 object,回傳對應的值,若無結果則先以語系物件查找,再無則回傳預設字串
* 語系物件可參考 store/global/globalLanguageInitState
*
* @param {string} key - 查詢的 key
* @param {object} obj - 物件內容
* @returns {string} return 物件中對應的內容
* @example
* getObjValue('myKey', {myKey: 'test'}) // return 'test'
*/

export const getObjValue = (key, obj) => {
return obj[key] || defaultLanguageLabels[key] || '系統錯誤'
}

Reducer Initial State

initial state 的基本要求:object 必須盡可能地預先宣告所有的 property,而非一開始只給空物件

讓其他開發者先一目了然有哪些 state 是很重要的,只設立空物件,後續才把添增 property 的 action 散落在各個程式碼,會讓維護性變得極為糟糕

// Bad
export const todoInitState = {}

// Good
export const todoInitState = {
isAddTodoDialogOpen: false,
isTodoEdit: null,
notification: {
type: null,
message: ''
},
getTodoListResponse: {
data: null,
statusCode: null,
msg: {
result: null,
resultMsg: '',
},
},
}

自定義 State 需撰寫 JSDoc

以上述範例來說,除了 getTodoListResponse 是 API response state,其他都是根據 container 或元件所需的自定義 state

自定義 state 需要撰寫 JSDoc 讓其他開發者得知 state 的格式與功能, 若 property 也是 object ,盡量獨立出 @typedef 詳盡定義 type

例如以下面例子,將 notification 獨立抽成 Notification type

為了可讀性與 TypeScript 命名慣例,巢狀中的子物件若有獨立出 typedef,遵照 UpperCamelCase 命名,且不需加入任何前綴

// bad
/**
* @typedef {Object} todoInitState
*/

// good
/**
* @typedef {Object} TodoInitState
*/

完整 JSDoc 標註範例 :

/**
* @typedef {Object} Notification
* @property {'error' | 'success' | null} type - 通知訊息類型
* @property {string} txt - 通知訊息內容
*/

/**
* @typedef {Object} TodoInitState
* @property {boolean} isAddTodoDialogOpen - 是否開啟新增待辦事項 dialog
* @property {boolean} isTodoEdit - 是否為編輯待辦事項
* @property {Notification} notification - 通知訊息
* @property {Object} getTodoListResponse - API 取得待辦事項列表
* @see {@link https://ui-dev-thk.migocorp.com/api/doc/ui.html#/campaign/getCampaign}
*/

/** @type {TodoInitState} */
export const todoInitState {
isAddTodoDialogOpen: false,
isTodoEdit: false,
notification: {
type: null,
message: '',
},
getTodoListResponse: {
isFetch: false,
data: null,
statusCode: null,
msg: {
result: null,
resultMsg: '',
},
},
}

* @property {'error' | 'success' | null} type - 通知訊息類型 這類有固定範圍的 property,若有需要可以使用 enum object 來處理,詳見「JSDoc 標註複雜 Object」

最後,使用 /** @type {TodoInitState} */ 對實際宣告的 object 進行標註,JSDoc 就會得知 todoInitState 使用 TodoInitState type

API Response State 的處理方式

API response state 是指 reducer state 中,存放 API 回傳結果的 property (通常也為一個 object)

API 回傳的資料格式較為複雜,也常有重複的屬性 (例如 statusCodemessage),不必特定獨立 @typedef ,標註為 Object 即可

但需使用 @see 來連結到該 API 的 Swagger 網址,也讓其他開發者方便查找 data 的資料結構

要注意的是,如果 Swagger 沒有清楚的結構說明,也十分建議 response data 進行 JSDoc 的標註

/**
* @typedef {Object} TodoInitState
* @property {Object} getTodoListResponse - API 取得待辦事項列表
* @see {@link https://ui-dev-thk.migocorp.com/api/doc/ui.html#/campaign/getCampaign}
*/

附註 : JSDoc 使用參考

其中 JSDoc 可以使用 「?」或是 「!」來標註 null 的情況

@property {?number} myProperty 代表這個 property 可能是 number 或是 null

@property {!number} myProperty 代表這個 property 會是 number,且必不為 null

JSDoc 何時需要加 「-」

/**
* 接收 key 和 object,回傳對應的值,若無結果則先以語系物件查找,再無則回傳預設字串
* 語系物件可參考 store/global/globalLanguageInitState
*
* @param {string} key - 查詢的 key
* @param {object} obj - 物件內容
* @returns {string} return 物件中對應的內容
* @example
* getObjValue('myKey', {myKey: 'test'}) // return 'test'
*/

export const getObjValue = (key, obj) => {
return obj[key] || defaultLanguageLabels[key] || '系統錯誤'
}

以目前在 VS Code 顯示的實測結果

  • @param@property 在敘述部分加入 「-」 在 VS Code 自動提示有更好的顯示效果 (會被渲染成 bullet point)
  • ==其餘標註的敘述則不需要加入「-」==,可能會有多餘的 dash 渲染

附註 : TypeScript Interface 要不要加入「I 」前綴

這篇 style guide 撰寫初期,有討論是否將 @typedef 命名加入 I 前綴

這是源自於許多人撰寫 TypeScript 會使用此慣例來命名 interface,甚至 tslint (deprecated)、typescript-eslint 也有納入此項規則 (非強制)

後來 TypeScript 社群的風氣逐漸不建議加上 I 前綴,所以 JSDoc 的 @typedef 維持 UpperCamelCase 即可

參考連結