TypeScript中如何正确标注flexifyParams函数的返回值类型
如何为flexifyParams函数正确标注TypeScript返回值类型?
问题背景
我正在编写一个TypeScript模块,其中包含flexifyParams函数:该函数接收一个对象,会调用对象中所有函数类型的属性,并将返回值赋值给对应属性;若属性非函数类型则直接保留原值。
JavaScript实现源码
import _ from 'lodash' export default function flexifyParams(params) { const composedObject = {} for (const [key, value] of Object.entries(params)) { composedObject[key] = _.isFunction(value) ? value() : value } return composedObject }
使用示例
const test = { x: () => 'hi', y: () => 123, z: () => ["a", "b", "c"], a: 'my string', } const P = flexifyParams(test) // P 等于: // { // x: 'hi', // y: 123, // z: ["a", "b", "c"], // a: 'my string', // }
当前TypeScript版本(存在类型问题)
import _ from 'lodash' export default function flexifyParams<PARAMS extends object>(params: PARAMS): PARAMS { const composedObject: { [index: string]: string | Symbol | number } = {} for (const [key, value] of Object.entries(params)) { composedObject[key] = _.isFunction(value) ? value() : value } return composedObject as PARAMS }
当前代码可正常运行,但返回值类型标注存在问题:返回对象的键与输入对象一致,但值类型应为对应函数属性的返回值,而非原属性类型。
解决方案
要解决这个问题,我们需要使用TypeScript的映射类型和条件类型,为返回值生成精确的类型:
核心思路
遍历输入对象的每个键,对每个属性值做判断:
- 如果属性是无参函数类型,提取它的返回值类型作为新属性的类型
- 如果属性不是函数类型,直接保留原类型
完整TypeScript实现
import _ from 'lodash' // 定义映射类型:将函数属性替换为其返回值类型,非函数属性保留原类型 type ResolvedParams<PARAMS extends object> = { [K in keyof PARAMS]: PARAMS[K] extends () => infer R ? R : PARAMS[K] } export default function flexifyParams<PARAMS extends object>(params: PARAMS): ResolvedParams<PARAMS> { // 使用映射类型定义composedObject,避免类型过宽 const composedObject: Partial<ResolvedParams<PARAMS>> = {} for (const [key, value] of Object.entries(params)) { // 类型断言key为PARAMS的键,避免Object.entries的类型丢失 const typedKey = key as keyof PARAMS composedObject[typedKey] = _.isFunction(value) ? value() : value as ResolvedParams<PARAMS>[typeof typedKey] } // 断言为完整的ResolvedParams类型,因为我们遍历了所有键 return composedObject as ResolvedParams<PARAMS> }
类型验证
使用之前的测试示例,TypeScript会自动推导P的类型为:
{ x: string; y: number; z: string[]; a: string; }
完全符合函数实际的返回值结构。
内容的提问来源于stack exchange,提问作者Islam Y-
相关产品推荐
相关产品推荐

