PAYATHON 2026

TypeScript 中如何在函数间传递数组并填充对象的数组属性?

排障赵师傅

用 await 取得 getGenericData() 返回的数组,再赋给整个数组属性:

pData.OpenViewModel = await this.getGenericData(
  p.pId,
  p.reportingDate,
  p.OpenViewModel_ST,
  p.OpenViewModel_TABLE
);

同时,把外层的 forEach 改成 for...of,让 getRawData() 等待每次请求完成。pData.OpenViewModel[] = ... 不是合法的数组赋值语法,赋值时要去掉属性名后面的 []。

为什么添加 await 后仍然报错?

注意区分以下类型:

表达式或声明类型含义
getGenericData(...)Promise<GenericViewModel[]>等待返回数组的 Promise
await getGenericData(...)GenericViewModel[]请求完成后得到的数组
OpenViewModel[index]GenericViewModel数组中的单个元素

getGenericData() 是 async 函数,即使内部已经执行了 await super.post(...),调用它得到的仍然是 Promise。调用方也需要使用 await 才能取得数组。

添加 await 后,如果错误变成:

Type 'GenericViewModel[]' is missing the following properties from type 'GenericViewModel'

说明赋值位置需要一个 GenericViewModel 对象,右侧却提供了整个数组。检查实际代码是否在给某个数组元素赋值、调用 push(array),或者把属性误声明成了 GenericViewModel。

题目中的空下标 OpenViewModel[] 本身就有语法问题,仅凭这一行无法准确判断该类型错误的原因。属性声明和赋值应分别写成:

// 类型声明中的 [] 表示数组
OpenViewModel: GenericViewModel[];

// 给整个数组属性赋值时,不带 []
pData.OpenViewModel = await this.getGenericData(/* 参数 */);

使用 for...of 完成数据填充

下面保留现有的 super.post() 和 this.apiPostResponse.data 取数方式,假定接口返回的数据已经符合相应模型。

原代码混用了 PScorecardModel 和 ProgramScorecardModel,集合属性也有 pcorecardModel 和 pScorecardModel 两种写法。示例统一使用 ProgramScorecardModel 和 pScorecardModel,实际使用时请与项目中的模型名称保持一致。

export interface GenericViewModel {
  rating: string;
  reportingDate: Date | null;
  comments: string;
  results: string;
  rtg_date: string;
  phase: string;
  denominator: number;
}

export interface ProgramScorecardModel {
  pId: string;
  OpenViewModel: GenericViewModel[];
}

export interface ScorecardModel {
  pScorecardModel: ProgramScorecardModel[];
}

将以下方法放在原有类中,PViewModel 沿用项目中的定义:

async getRawData(): Promise<ScorecardModel> {
  const criteria = {
    storedProcedure: 'sp_Get_Data_For_ESM',
  };

  await super.post(
    'universal-sp-pass-thru/spPassThroughnoBody',
    criteria,
    'api-eprs'
  );

  const pList: PViewModel[] = this.apiPostResponse.data;

  const scorecardData: ScorecardModel = {
    pScorecardModel: [],
  };

  for (const p of pList) {
    const pData: ProgramScorecardModel = {
      pId: p.pId,
      OpenViewModel: [],
    };

    pData.OpenViewModel = await this.getGenericData(
      p.pId,
      p.reportingDate,
      p.OpenViewModel_ST,
      p.OpenViewModel_TABLE
    );

    scorecardData.pScorecardModel.push(pData);
  }

  return scorecardData;
}

async getGenericData(
  pId: string,
  reportingDate: Date | null,
  ised: string,
  tablename: string
): Promise<GenericViewModel[]> {
  const body = {
    pId,
    reportingDate,
    ised,
    tablename,
  };

  const criteria = {
    storedProcedure: 'sp_GetScorecard',
    body,
  };

  await super.post(
    'sword-universal-sp-pass-thru/spPassThrough',
    criteria,
    'api-eprs'
  );

  const items: GenericViewModel[] = this.apiPostResponse.data;
  return items;
}

调用方也要等待结果:

const scorecardData = await this.getRawData();

getRawData() 返回组装好的对象后,调用方就可以继续使用。如果项目将结果保存在组件属性中,也可以在循环结束后赋给相应属性。

为什么不能只把 forEach 回调改成 async?

给回调加上 async 后,可以在其中使用 await,但 forEach() 不会等待回调返回的 Promise:

pList.forEach(async (p) => {
  // await ...
});

因此,外层的 getRawData() 可能在数据填充完成前就结束。写成 await pList.forEach(...) 也无效,因为 forEach() 返回的是 undefined。

在 for...of 中使用 await,每轮请求会依次完成。当前代码通过共享属性 this.apiPostResponse 读取响应,顺序执行也能避免该循环内多个请求同时写入这个属性。

如果需要并发请求,应先确认每次调用 super.post() 都能直接取得各自的响应,再考虑使用 Promise.all()。它返回 Promise,并不代表这个 Promise 兑现后的值就是响应对象。

替换数组和追加元素怎样选择?

如果接口返回的数据就是该属性的全部内容,直接赋值:

const items = await this.getGenericData(
  p.pId,
  p.reportingDate,
  p.OpenViewModel_ST,
  p.OpenViewModel_TABLE
);

pData.OpenViewModel = items;

如果要保留原有元素并追加返回的数据,使用展开语法:

pData.OpenViewModel.push(...items);

不要写成:

pData.OpenViewModel.push(items);

这里的 push() 接收一个或多个 GenericViewModel 元素,items 的类型则是 GenericViewModel[]。

是否需要用 map() 重新构造对象?

如果接口字段已经符合 GenericViewModel,直接返回数组即可。用 map() 逐字段复制后,得到的仍然是 GenericViewModel[],无法解决 Promise 未解包或把数组当成单个元素的问题。

需要重命名字段、转换值或补充数据时,再使用映射。例如,接口通过 JSON 返回日期字符串时,声明 reportingDate: Date | null 不会自动将字符串转换为 Date,仍需按接口约定进行转换。

const items: GenericViewModel[] = this.apiPostResponse.data 也只提供静态类型检查。如果 data 是 any,这条声明无法验证运行时数据。应在接口层为响应定义类型,并按实际需要校验数据。

备注:内容仅供参考。