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

如何重构含多||条件的数组遍历TypeScript函数?

重构思路与优化方案

针对你这个TypeScript函数,这里提供几个实用的重构方向,既提升代码可读性和维护性,也能优化执行效率:

1. 先明确类型,移除any

原函数大量使用any类型,完全丢失了TypeScript的类型优势。先定义清晰的接口和枚举,让代码更安全:

// 先明确枚举(如果项目里已有,直接复用即可)
enum CallTimingType {
  SpecificDates = 'SpecificDates',
  AnyTime = 'AnyTime',
  Monthly = 'Monthly',
  OnPaymentDates = 'OnPaymentDates',
  AnyInterestAdjustmentDate = 'AnyInterestAdjustmentDate'
}

// 定义调用计划项的接口
interface CallScheduleItem {
  CallTimingType: CallTimingType;
}

// 定义security的接口
interface Security {
  IsCallable: boolean;
}

// 定义返回值的接口
interface CallInfo {
  CallTimingType: 'Not Callable' | 'Discrete' | 'Continuous';
  isCheckMark: boolean | null;
}

2. 用映射表简化条件判断

原函数的多分支if判断冗余且难维护,用映射表将枚举值和结果类型直接关联,后续新增枚举值只需修改映射表:

版本一:保留原遍历逻辑(最后一个匹配项生效)

getCallInfo = (callSch: { Calls: CallScheduleItem[] }, security: Security): CallInfo => {
  const defaultCallInfo: CallInfo = {
    CallTimingType: 'Not Callable',
    isCheckMark: null,
  };

  if (!security.IsCallable) return defaultCallInfo;

  // 枚举到结果类型的映射表
  const timingTypeMap: Record<CallTimingType, 'Discrete' | 'Continuous'> = {
    [CallTimingType.SpecificDates]: 'Discrete',
    [CallTimingType.AnyTime]: 'Continuous',
    [CallTimingType.Monthly]: 'Continuous',
    [CallTimingType.OnPaymentDates]: 'Continuous',
    [CallTimingType.AnyInterestAdjustmentDate]: 'Continuous'
  };

  const callInfo = { ...defaultCallInfo };

  callSch.Calls.forEach(el => {
    const mappedType = timingTypeMap[el.CallTimingType];
    if (mappedType) {
      callInfo.CallTimingType = mappedType;
      callInfo.isCheckMark = true;
    }
  });

  return callInfo;
};

版本二:提前终止遍历(优化性能)

原函数会遍历所有Calls元素,但实际上如果遇到Continuous类型的项,后续遍历不会改变最终结果(因为Continuous会覆盖Discrete)。可以提前终止遍历,提升执行效率:

getCallInfo = (callSch: { Calls: CallScheduleItem[] }, security: Security): CallInfo => {
  const defaultCallInfo: CallInfo = {
    CallTimingType: 'Not Callable',
    isCheckMark: null,
  };

  if (!security.IsCallable) return defaultCallInfo;

  const callInfo = { ...defaultCallInfo };
  let foundContinuous = false;

  // 优先查找Continuous类型,找到就终止遍历
  for (const el of callSch.Calls) {
    if ([
      CallTimingType.AnyTime,
      CallTimingType.Monthly,
      CallTimingType.OnPaymentDates,
      CallTimingType.AnyInterestAdjustmentDate
    ].includes(el.CallTimingType)) {
      callInfo.CallTimingType = 'Continuous';
      callInfo.isCheckMark = true;
      foundContinuous = true;
      break;
    }
  }

  // 没找到Continuous,再检查是否有Discrete类型
  if (!foundContinuous) {
    const hasDiscrete = callSch.Calls.some(el => el.CallTimingType === CallTimingType.SpecificDates);
    if (hasDiscrete) {
      callInfo.CallTimingType = 'Discrete';
      callInfo.isCheckMark = true;
    }
  }

  return callInfo;
};

版本三:用reduce简化遍历逻辑

如果喜欢函数式风格,可以用reduce一次性完成遍历和结果累积:

getCallInfo = (callSch: { Calls: CallScheduleItem[] }, security: Security): CallInfo => {
  const defaultCallInfo: CallInfo = {
    CallTimingType: 'Not Callable',
    isCheckMark: null,
  };

  if (!security.IsCallable) return defaultCallInfo;

  const timingTypeMap: Record<CallTimingType, 'Discrete' | 'Continuous'> = {
    [CallTimingType.SpecificDates]: 'Discrete',
    [CallTimingType.AnyTime]: 'Continuous',
    [CallTimingType.Monthly]: 'Continuous',
    [CallTimingType.OnPaymentDates]: 'Continuous',
    [CallTimingType.AnyInterestAdjustmentDate]: 'Continuous'
  };

  return callSch.Calls.reduce((acc, el) => {
    const mappedType = timingTypeMap[el.CallTimingType];
    return mappedType ? { ...acc, CallTimingType: mappedType, isCheckMark: true } : acc;
  }, defaultCallInfo);
};

重构核心要点

  • 类型安全:移除any,用接口和枚举明确类型,减少潜在bug,提升代码可读性。
  • 逻辑简化:映射表替代多分支if,后续维护只需修改映射表,降低代码复杂度。
  • 性能优化:如果业务允许,提前终止遍历,避免不必要的循环。
  • 无副作用:通过对象展开创建新对象,避免直接修改初始对象,让逻辑更纯净。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 18:48:24