如何为Firestore类型化update函数实现POJO字段路径及值类型定义
实现方案
类型定义
// 辅助类型:给路径加.前缀 type DotPrefix<T extends string> = T extends "" ? "" : `.${T}`; // 核心类型1:提取所有合法的字段路径(不进入数组内部,和原有逻辑一致) export type DeepKeyOf<T> = ( T extends object ? { [K in Extract<keyof T, string>]: T[K] extends Array<unknown> ? `${K}` : `${K}` | `${K}${DotPrefix<DeepKeyOf<T[K]>>}`; }[Extract<keyof T, string>] : "" ) extends infer D ? Extract<D, string> : never; // 核心类型2:根据字段路径获取对应的值类型 type DeepPathValue<T, P extends string> = P extends `${infer K}.${infer Rest}` ? K extends keyof T ? T[K] extends Array<unknown> ? T[K] // 遇到数组直接返回数组类型,不递归 : DeepPathValue<T[K], Rest> : never : P extends keyof T ? T[P] : never; // 核心类型3:嵌套字段路径映射类型 export type NestedFieldPaths<T> = { [P in DeepKeyOf<T>]?: DeepPathValue<T, P> }; // 最终Update参数类型 export type UpdateParam<T> = Partial<T> | NestedFieldPaths<T>;
测试验证
用示例文档类型测试效果:
type ExampleDocument = { a: { b: { c: string; d?: number; arr: number[] } }; arr: string[]; }; // NestedFieldPaths<ExampleDocument> 计算结果如下,完全符合预期: // { // "a"?: { b: { c: string; d?: number; arr: number[] } }; // "arr"?: string[]; // "a.b"?: { c: string; d?: number; arr: number[] }; // "a.b.c"?: string; // "a.b.d"?: number; // "a.b.arr"?: number[]; // } // 类型校验测试 const update1: UpdateParam<ExampleDocument> = { arr: ["1", "2"] }; // 合法 const update2: UpdateParam<ExampleDocument> = { "a.b.c": "test" }; // 合法 const update3: UpdateParam<ExampleDocument> = { "a.b.d": 123 }; // 合法 const update4: UpdateParam<ExampleDocument> = { a: { b: { c: "test", arr: [1,2] } } }; // 合法
Firestore Update函数封装示例
import { DocumentReference, updateDoc } from "firebase/firestore"; async function updateDocument<T extends object>( ref: DocumentReference<T>, data: UpdateParam<T> ) { await updateDoc(ref, data as any); }
内容的提问来源于stack exchange,提问作者Thijs Koerselman
相关产品推荐
相关产品推荐

