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 回傳的資料格式較為複雜,也常有重複的屬性 (例如
statusCode
、message
),不必特定獨立@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
即可
參考連結