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

TypeScript如何实现返回类型与泛型一致的单对象/数组反序列化mapper

问题背景

我们需要对REST接口返回的JSON数据做反序列化,这类接口既可能返回单个对象,也可能返回多个同类型对象组成的数组。

接口返回示例

单个客户查询接口

请求路径:/api/customer/1
返回值:

{ "name": "Matt", "phone": "+010101010" }

多个客户查询接口

请求路径:/api/customer/
返回值:

[
   {"name": "Matt", "phone": "+010101010"},
   {"name": "John", "phone": "+99999999"},
   {"name": "Doe", "phone": "+123131321"}
]

现有实现问题

当前已实现可用的反序列化函数如下:

const mapper = <T>(type: DTOResponse<T>, data: any): T | T[] | null => {
    let result: T | T[];

    if (Array.isArray(data)) {
        result = data.map(x => plainToClass(type, x));
    }
    else {
        result = plainToClass(type, data);
    }

    return result;
 }

 const resAsArrayObj = mapper<DtoModel>(DtoModel, dtoArray);
 const resAsSingleObj = mapper<DtoModel>(DtoModel, dtoSingleObj);

上述代码可正常运行,但缺点是返回值类型为联合类型T | T[],无法和传入的泛型参数直接对应。我们期望泛型传入单个类型时返回单个对象,泛型传入数组类型时返回对象数组。

解决方案

借助TypeScript条件类型实现泛型自动推导,改造后的代码如下:

// DTO类构造函数类型定义
type DTOResponse<T> = new () => T;

// 泛型解包:如果T是数组类型则提取元素类型,否则返回T本身
type UnpackArray<T> = T extends (infer U)[] ? U : T;

// 改造后的mapper函数
function mapper<T>(dtoClazz: DTOResponse<UnpackArray<T>>, data: any): T {
  if (Array.isArray(data)) {
    return data.map(item => plainToClass(dtoClazz, item)) as T;
  }
  return plainToClass(dtoClazz, data) as T;
}

调用示例

完全符合预期的类型匹配效果:

// resAsArrayObj 类型自动为 DtoModel[]
const resAsArrayObj = mapper<DtoModel[]>(DtoModel, dtoArray);
// resAsSingleObj 类型自动为 DtoModel
const resAsSingleObj = mapper<DtoModel>(DtoModel, dtoSingleObj);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 08:12:03