TYPESCRIPT / PRACTICE

表单字段变更建模

从表单值类型生成更新消息,保留字段和值的对应关系并限制可编辑范围。

本章目录CONTENTS ↓

表单更新消息需要同时记录字段名和新值。如果它们独立取联合,就可能把数字写入标题字段。我们希望消息类型随表单定义变化,并且只允许更新选定字段。

需要的基础是泛型、映射与索引访问;本章组合这些机制表达业务约束。

迁移到表单字段

表单更新消息要说明“改了哪个字段、改成什么值”。字段名必须决定值的类型,否则标题字段也可能收到数字。与事件消息一样,把字段和值放进同一个成员,再由已有表单类型生成这些成员即可。

保留字段与值的对应关系

ts
type FormValues = {
  title: string; count: number; enabled: boolean;
};
type FieldChange<T> = {
  [K in keyof T]: { field: K; value: T[K] }
}[keyof T];
// FieldChange<FormValues>:
// { field: "title"; value: string }
// | { field: "count"; value: number }
// | { field: "enabled"; value: boolean }

value 必须使用当前 K。若改为 T[keyof T],每个成员都会接收全部属性值的联合,title 配数字也会被允许。

只允许修改选定字段

某些表单字段仅允许读取,更新接口应只接收可编辑字段。此时应缩小遍历的键集合,而不是先允许所有字段再交给调用者避开它们。

ts
type ChangesFor<T, Keys extends keyof T> = {
  [K in Keys]: { field: K; value: T[K] }
}[Keys];

type Editable = ChangesFor<FormValues, "title" | "enabled">;

映射对象只有 Keys 中的键,所以尾部也用 Keys。这里若改用 keyof T,就多出了映射对象没有的 count

示例聚焦必填属性;可选属性和特殊类型需要另行考虑。

检查允许的更新

ts
const change: FieldChange<FormValues> = { field: "title", value: "新标题" };
const editable: Editable = { field: "enabled", value: true };
// { field: "title", value: 3 } 不满足 FieldChange<FormValues>。
// count 没有进入 Editable 的键集合。

每个成员内部用同一个 K 配对字段和值,最后才取成联合。这比把所有字段和值分别取联合更准确。若业务确实允许独立组合,两组独立联合也可以表达那种不同的需求。

官方阅读

这一页,先记到这里。