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

如何正确标注计算含可选属性对象属性平均值的函数类型?

解决DogSample类型包装函数的类型匹配问题

首先明确你的DogSample类型结构(示例定义):

type DogSample = {
  // 5个必选犬种体重属性
  pug: number;
  beagle: number;
  goldenRetriever: number;
  poodle: number;
  bulldog: number;
  // 可选属性:rottweiler仅在dalmatian存在时出现
  dalmatian?: number;
  rottweiler?: number;
  // 任意无关属性
  [key: string]: unknown;
};

以及对应的三个计算函数(示例):

// 计算5种必选犬种的平均体重
function calc5Mean(sample: Pick<DogSample, 'pug' | 'beagle' | 'goldenRetriever' | 'poodle' | 'bulldog'>): number {
  return (sample.pug + sample.beagle + sample.goldenRetriever + sample.poodle + sample.bulldog) / 5;
}

// 计算6种(必选+dalmatian)的平均体重
function calc6Mean(sample: Pick<DogSample, 'pug' | 'beagle' | 'goldenRetriever' | 'poodle' | 'bulldog' | 'dalmatian'>): number {
  return (sample.pug + sample.beagle + sample.goldenRetriever + sample.poodle + sample.bulldog + sample.dalmatian) / 6;
}

// 计算7种(必选+dalmatian+rottweiler)的平均体重
function calc7Mean(sample: Pick<DogSample, 'pug' | 'beagle' | 'goldenRetriever' | 'poodle' | 'bulldog' | 'dalmatian' | 'rottweiler'>): number {
  return (sample.pug + sample.beagle + sample.goldenRetriever + sample.poodle + sample.bulldog + sample.dalmatian + sample.rottweiler) / 7;
}

方案一:使用函数重载

通过函数重载定义不同参数类型对应的返回逻辑,让TypeScript自动匹配合适的计算函数:

// 重载签名:覆盖三种参数情况
function calcMeanDogSample(sample: DogSample & Required<Pick<DogSample, 'dalmatian' | 'rottweiler'>>): number;
function calcMeanDogSample(sample: DogSample & Required<Pick<DogSample, 'dalmatian'>>): number;
function calcMeanDogSample(sample: DogSample): number;

// 函数实现
function calcMeanDogSample(sample: DogSample): number {
  // 先判断是否同时存在dalmatian和rottweiler
  if (typeof sample.dalmatian === 'number' && typeof sample.rottweiler === 'number') {
    return calc7Mean(sample as DogSample & Required<Pick<DogSample, 'dalmatian' | 'rottweiler'>>);
  }
  // 再判断是否仅存在dalmatian
  else if (typeof sample.dalmatian === 'number') {
    return calc6Mean(sample as DogSample & Required<Pick<DogSample, 'dalmatian'>>);
  }
  // 仅存在必选属性的情况
  else {
    return calc5Mean(sample);
  }
}

方案二:使用类型守卫+辅助类型

通过自定义类型守卫,让TypeScript精准识别参数的属性存在情况,无需类型断言:

// 定义辅助类型,明确属性存在的情况
type HasDalmatian = DogSample & { dalmatian: number };
type HasBothDogs = HasDalmatian & { rottweiler: number };

// 类型守卫函数:判断是否包含dalmatian
function hasDalmatian(sample: DogSample): sample is HasDalmatian {
  return typeof sample.dalmatian === 'number';
}

// 类型守卫函数:判断是否同时包含dalmatian和rottweiler
function hasBothDogs(sample: DogSample): sample is HasBothDogs {
  return hasDalmatian(sample) && typeof sample.rottweiler === 'number';
}

// 包装函数实现
function calcMeanDogSample(sample: DogSample): number {
  if (hasBothDogs(sample)) {
    return calc7Mean(sample);
  } else if (hasDalmatian(sample)) {
    return calc6Mean(sample);
  } else {
    return calc5Mean(sample);
  }
}

方案说明

  • 直接使用DogSample类型时,TypeScript无法保证可选属性dalmatian/rottweiler的存在,因此传给要求这些属性必选的calc6Mean/calc7Mean会报错。
  • 使用Required<DogSample>则会限制参数必须包含所有可选属性,无法接收仅含必选属性的DogSample实例。
  • 上述两种方案通过区分参数的属性存在情况,既允许传入任意合法的DogSample实例,又能在调用对应计算函数时保证类型安全,完美解决类型不匹配问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 07:45:39