改寫表單 CRUD 流程
問題描述
在改寫列表/表單相關的 CRUD 流程時,表格操作列(檢視、編輯、刪除、匯出等)若散落字串或寬鬆型別,後續擴充或換頁複製時容易不一致。以下整理一套可組合的常數物件與型別安全的 handler 對照表做法。
基本表格操作:用 as const 物件取代部分 enum 場景
相較於 enum,常數物件加上 as const 的好處是容易用展開運算子組合、擴充新功能時不必全部擠在同一枚舉裡。缺點是 TypeScript 無法在編譯期證明「所有 value 都不重複」,需靠命名慣例、code review 或測試補強。
ts
export const BaseTableAction = {
View: "view",
Edit: "edit",
Delete: "delete",
Copy: "copy",
} as const;組合出特定模組可用的 Action
共用基底再疊加該頁或該模組專用操作,避免重複定義。
ts
export const AdvancedTableAction = {
...BaseTableAction,
Export: "export",
Archive: "archive",
} as const;
export const FeatureTableAction = {
...BaseTableAction,
Calculate: "calculate",
Download: "download",
} as const;單一列表頁:擴充對照表並縮小「實際會實作的操作」聯集
以下為示意:假設某列表列型別為 EntityRow,分頁請求/回應型別由專案 API 層定義(此處以佔位名稱帶過)。
ts
// 沿用前段已定義的 BaseTableAction
/** 本頁在基底操作外再掛載的「語意化」操作鍵(value 請保持唯一) */
export const EntityTableActionMap = {
...BaseTableAction,
RemoveLink: "RemoveLink",
OpenConfirmModal: "OpenConfirmModal",
} as const;
export type EntityTableActionValue =
(typeof EntityTableActionMap)[keyof typeof EntityTableActionMap];
/** 僅列出「本表有實作 handler」的操作,避免 Record 必須填滿整張大表 */
export type DataTableImplementedAction =
| typeof EntityTableActionMap.Delete
| typeof EntityTableActionMap.RemoveLink
| typeof EntityTableActionMap.OpenConfirmModal;
export type ActionHandler = (row?: EntityRow) => void | Promise<void>;
/** 對照表,將操作與對應的 handler 進行對應,作為示意,不撰寫實際的handler function */
const actionMap: Record<DataTableImplementedAction, ActionHandler> = {
[EntityTableActionMap.Delete]: handleDelete,
[EntityTableActionMap.RemoveLink]: handleRemoveLink,
[EntityTableActionMap.OpenConfirmModal]: (row) => {
if (!row) return;
handleOpenConfirmModal(row);
},
};與模板/下拉選單的銜接
在欄位模板中為 slot 參數標上列型別後,handler 可經由 actionMap 以常數為 key 呼叫,減少魔術字串。
vue
<template>
<el-table-column
:label="$t('…')"
prop="action"
align="center"
min-width="90">
<template #default="{ row }: { row: EntityRow }">
<div>
<DropdownList
:shows="['delete']"
:custom-name="{ delete: $t('…') }"
@delete="actionMap[EntityTableActionMap.OpenConfirmModal](row)" />
</div>
</template>
</el-table-column>
</template>實務上會再確認的幾點
- 常數 value 是否全域唯一:若與其他模組共用字串,建議前綴或命名空間化,避免事件/權限/log 對應錯對象。(如果有這種需求的話)
DataTableImplementedAction與actionMap要同步:新增操作時記得兩邊一併更新,必要時可用型別讓Record強制鍵齊全。- 無法靜態檢查 value 碰撞:若團隊在意,可寫小腳本在 CI 掃描重複 value,或維護單一註冊表產生子集。
以上模式適合「多列表頁共用基底操作、各頁再長出自己的一組語意化動作」的 CRUD/列表流程。
