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

如何在TypeScript中正确定义多类型对象映射函数?

TypeScript联合类型数组映射的类型兼容问题解决

问题代码

type ObjectA = {
  id: number;
  x: string;
  y: string;
  z: string;
}

type ObjectB = {
  id: number;
  a: string;
  b: string;
  c: string;
}

type Objects = (ObjectA | ObjectB)[]

type MappedObject = {
  id: number;
  a: string;
  s: string;
  d: string;
}

type MapFn = (obj: Objects) => MappedObject[];

const mapObjectA: MapFn = (obj: ObjectA[]) => obj.map(el => ({
  id: el.id,
  a: el.x,
  s: el.y,
  d: el.z
}));

const mapObjectB: MapFn = (obj: ObjectB[]) => obj.map(el => ({
  id: el.id,
  a: el.a,
  s: el.b,
  d: el.c
}));

报错信息

Type 'Objects' is not assignable to type 'ObjectA[]'.
Type 'ObjectA | ObjectB' is not assignable to type 'ObjectA'.
Type 'ObjectB' is missing the following properties from type 'ObjectA': x, y, z.

问题根源

你定义的MapFn要求参数是混合了ObjectA和ObjectB的联合数组,但mapObjectA和mapObjectB却声明只接受单一类型的数组。TypeScript的类型系统无法保证传入MapFn的数组是纯ObjectA或纯ObjectB,因此会抛出类型不兼容错误——这是联合类型的核心特性:它代表"可能是A,也可能是B"的不确定状态,而非"要么全是A,要么全是B"的二选一状态。

合规解决方案

方案1:泛型函数适配单一类型数组

如果希望保留独立的映射函数,修改MapFn为泛型类型,让每个函数只处理对应类型的数组:

type ObjectA = {
  id: number;
  x: string;
  y: string;
  z: string;
}

type ObjectB = {
  id: number;
  a: string;
  b: string;
  c: string;
}

type Objects = (ObjectA | ObjectB)[]

type MappedObject = {
  id: number;
  a: string;
  s: string;
  d: string;
}

// 泛型MapFn,约束输入为ObjectA或ObjectB的数组
type MapFn<T extends ObjectA | ObjectB> = (obj: T[]) => MappedObject[];

const mapObjectA: MapFn<ObjectA> = (obj) => obj.map(el => ({
  id: el.id,
  a: el.x,
  s: el.y,
  d: el.z
}));

const mapObjectB: MapFn<ObjectB> = (obj) => obj.map(el => ({
  id: el.id,
  a: el.a,
  s: el.b,
  d: el.c
}));

这样每个函数的输入类型明确,TypeScript会严格校验传入的数组类型,不会再报错。

方案2:判别式联合+单一处理函数(推荐)

给ObjectA和ObjectB添加判别属性,让TypeScript能自动区分不同类型,这种方式扩展性最强,新增类型时只需补充判别值和处理分支:

// 添加type字段作为判别式,明确区分类型
type ObjectA = {
  type: 'A';
  id: number;
  x: string;
  y: string;
  z: string;
}

type ObjectB = {
  type: 'B';
  id: number;
  a: string;
  b: string;
  c: string;
}

type Objects = (ObjectA | ObjectB)[]

type MappedObject = {
  id: number;
  a: string;
  s: string;
  d: string;
}

const mapObjects: (obj: Objects) => MappedObject[] = (objs) => {
  return objs.map(obj => {
    switch(obj.type) {
      case 'A':
        return {
          id: obj.id,
          a: obj.x,
          s: obj.y,
          d: obj.z
        };
      case 'B':
        return {
          id: obj.id,
          a: obj.a,
          s: obj.b,
          d: obj.c
        };
      // 穷尽检查,新增类型时TypeScript会提示补充分支
      default:
        throw new Error(`未知对象类型: ${(obj as never).type}`);
    }
  });
};

判别式联合让TypeScript在编译阶段就能确保所有类型都被处理,避免遗漏。

方案3:类型守卫函数(适合无法修改原类型的场景)

如果不能给原类型添加判别属性,可以定义类型谓词函数做类型检查,避免重复写in判断:

type ObjectA = {
  id: number;
  x: string;
  y: string;
  z: string;
}

type ObjectB = {
  id: number;
  a: string;
  b: string;
  c: string;
}

type Objects = (ObjectA | ObjectB)[]

type MappedObject = {
  id: number;
  a: string;
  s: string;
  d: string;
}

// 类型谓词函数,判断是否为ObjectA
function isObjectA(obj: ObjectA | ObjectB): obj is ObjectA {
  return 'x' in obj;
}

// 类型谓词函数,判断是否为ObjectB
function isObjectB(obj: ObjectA | ObjectB): obj is ObjectB {
  return 'a' in obj;
}

const mapObjects: (obj: Objects) => MappedObject[] = (objs) => {
  return objs.map(obj => {
    if (isObjectA(obj)) {
      return {
        id: obj.id,
        a: obj.x,
        s: obj.y,
        d: obj.z
      };
    } else {
      return {
        id: obj.id,
        a: obj.a,
        s: obj.b,
        d: obj.c
      };
    }
  });
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 02:55:28