You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用泛型TypeScript简化嵌套JSON,实现Person模型反序列化

用泛型TypeScript方案处理嵌套JSON反序列化,移除多余data层

问题背景

咱们先明确下需求:

  • 接口返回的嵌套JSON结构:
    {
      "results": {
        "data": { 
          "id":"93cba9bd-2969-3214-b26f-7f42d20241a4", 
          "first_name":"PSU", 
          "last_name":"Bot", 
          "profile": { "data":{"about":"i am so happy"} } 
        } 
      }
    }
    
  • 目标Person模型定义:
    export class Person extends BaseModel {
      first_name: string;
      last_name: string;
      profile: Profile; // 要求这里直接是Profile类型,不再包含data嵌套
    }
    
    export class Profile extends BaseModel {
      about: string;
    }
    

泛型解决方案

咱们可以通过泛型工具类型定义类型映射规则,再配合递归转换函数实现数据结构的自动扁平化,具体步骤如下:

1. 定义泛型工具类型,解开嵌套的data层

首先写一个递归的工具类型,用来自动提取所有嵌套层级里的data属性值类型:

// 递归解开所有带data的嵌套结构
type UnwrapData<T> = T extends { data: infer U } 
  ? UnwrapData<U> 
  : T;

// 定义API返回的通用结构类型
type ApiResponse<T> = { results: { data: T } };

这个UnwrapData类型会自动递归检查类型是否包含data属性,如果有就提取data的类型继续处理,直到没有嵌套的data为止。

2. 编写递归转换函数,处理实际数据

接下来写一个泛型函数,把API返回的嵌套数据转换成符合目标模型的结构:

function unwrapApiData<T>(response: ApiResponse<unknown>): UnwrapData<ApiResponse<unknown>> {
  // 递归遍历对象,解开所有data嵌套
  function deepUnwrap(obj: unknown): unknown {
    // 如果当前对象有data属性,直接递归处理data的值
    if (typeof obj === 'object' && obj !== null && 'data' in obj) {
      return deepUnwrap((obj as { data: unknown }).data);
    }
    // 处理数组:遍历每个元素递归解开
    if (Array.isArray(obj)) {
      return obj.map(deepUnwrap);
    }
    // 处理普通对象:遍历每个属性递归解开
    if (typeof obj === 'object' && obj !== null) {
      const unwrappedObj: Record<string, unknown> = {};
      for (const key in obj) {
        unwrappedObj[key] = deepUnwrap((obj as Record<string, unknown>)[key]);
      }
      return unwrappedObj;
    }
    // 基础类型直接返回
    return obj;
  }

  return deepUnwrap(response) as UnwrapData<typeof response>;
}

3. 使用示例

现在就可以用这个函数处理API返回的数据,然后映射到Person模型:

// 模拟接口返回的数据
const apiResponse = {
  "results": {
    "data": { 
      "id":"93cba9bd-2969-3214-b26f-7f42d20241a4", 
      "first_name":"PSU", 
      "last_name":"Bot", 
      "profile": { "data":{"about":"i am so happy"} } 
    } 
  }
};

// 解开嵌套的data层
const unwrappedData = unwrapApiData(apiResponse);
// 此时unwrappedData的结构是:{ id: string; first_name: string; last_name: string; profile: { about: string } }

// 映射到Person模型(如果BaseModel有构造逻辑,也可以在这里处理)
const person = Object.assign(new Person(), unwrappedData);

console.log(person.profile.about); // 输出:i am so happy

4. 优化类型精准度(可选)

如果想让转换函数的返回类型更精准,可以给unwrapApiData指定更明确的泛型约束:

type UnwrappedApiResult<T> = UnwrapData<ApiResponse<T>>;

function unwrapApiData<T>(response: ApiResponse<T>): UnwrappedApiResult<T> {
  // 内部实现同上
}

这样一来,TypeScript就能更准确地推断转换后的数据类型,给你更完善的类型提示。

内容的提问来源于stack exchange,提问作者prog_24

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:02:51