TypeScript中基于DocumentModel过滤JSON的通用映射器实现
实现TypeScript通用JSON映射器,仅保留与指定类型匹配的键值对
需求很明确:需要一个工具,把任意JSON对象转换成符合DocumentModel类型的结构,只保留该类型定义中声明的键值对,不管输入里有多少额外字段。
目标类型定义
首先明确DocumentModel的类型(补充示例中缺失的DocType定义):
type DocType = string; type DocumentModel = { id?: string | null, docType: DocType, accountId?: string | null, updatedBy: string | null; };
输入输出示例
输入JSON:
{ "id": "80e474bc-7e28-4e28-ad43-c031da0f297b", "docType": "80e474bc-7e28-4e28-9b11-2259cf68f91e", "type": "INDIVIDUAL", "accountId": "80e474bc-7e28-4e28-ad43-c031da0f297b", "account": { "id": "80e474bc-7e28-4e28-ad43-c031da0f297b", "type": "INDIVIDUAL", "updatedAt": "2023-04-05T11:53:17.587Z" }, "attributes": "{\"identity\":\"12345\",\"name\":\"nicky\"}", "questionnaire": null, "owner": "bddfe953-0c1c-4aa4-9b11-2259cf68f91e", "comments": null, "updatedBy": "bddfe953-0c1c-4aa4-9b11-2259cf68f91e", "createdAt": "2023-04-05T11:53:17.587Z", "updatedAt": "2023-04-05T11:53:17.587Z" }
期望输出:
{ "id": "80e474bc-7e28-4e28-ad43-c031da0f297b", "docType": "80e474bc-7e28-4e28-9b11-2259cf68f91e", "accountId": "80e474bc-7e28-4e28-ad43-c031da0f297b", "updatedBy": "bddfe953-0c1c-4aa4-9b11-2259cf68f91e" }
实现方案
核心思路
TypeScript类型仅存在于编译阶段,运行时无法直接读取类型信息,因此需要手动维护目标类型的键名数组,同时通过类型约束保证数组和类型的一致性,之后从输入对象中筛选出这些键对应的键值对。
完整代码实现
type DocType = string; type DocumentModel = { id?: string | null, docType: DocType, accountId?: string | null, updatedBy: string | null; }; // 定义DocumentModel的键数组,用as const让TS推断为字面量类型,确保和类型键完全匹配 const documentModelKeys = ['id', 'docType', 'accountId', 'updatedBy'] as const; // 从键数组生成对应的键类型,编译时检查数组和类型的一致性 type DocumentModelKey = typeof documentModelKeys[number]; // 通用映射函数:接受任意对象和目标键数组,返回筛选后的对象 function mapToModel<T extends Record<string, unknown>, K extends readonly string[]>( input: T, keys: K ): Pick<T, K[number]> { const result = {} as Pick<T, K[number]>; keys.forEach(key => { // 只保留输入对象中存在的键,避免可选字段导致的undefined if (key in input) { result[key as keyof typeof result] = input[key] as Pick<T, K[number]>[typeof key]; } }); return result; } // 使用示例 const inputJson = { "id": "80e474bc-7e28-4e28-ad43-c031da0f297b", "docType": "80e474bc-7e28-4e28-9b11-2259cf68f91e", "type": "INDIVIDUAL", "accountId": "80e474bc-7e28-4e28-ad43-c031da0f297b", "account": { "id": "80e474bc-7e28-4e28-ad43-c031da0f297b", "type": "INDIVIDUAL", "updatedAt": "2023-04-05T11:53:17.587Z" }, "attributes": "{\"identity\":\"12345\",\"name\":\"nicky\"}", "questionnaire": null, "owner": "bddfe953-0c1c-4aa4-9b11-2259cf68f91e", "comments": null, "updatedBy": "bddfe953-0c1c-4aa4-9b11-2259cf68f91e", "createdAt": "2023-04-05T11:53:17.587Z", "updatedAt": "2023-04-05T11:53:17.587Z" }; const output = mapToModel(inputJson, documentModelKeys); console.log(output);
优势说明
- 通用性:只要替换
documentModelKeys数组,就能适配其他类型的映射需求 - 类型安全:编译时会检查键数组和目标类型的键是否一致,避免手动写错键名
- 灵活处理可选字段:自动忽略输入中不存在的可选字段,不会在结果中生成undefined
内容的提问来源于stack exchange,提问作者Nicky Shankar
相关产品推荐
相关产品推荐

