如何正确标注计算含可选属性对象属性平均值的函数类型?
解决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
相关产品推荐
相关产品推荐

