如何实现可从对象转换函数自动推断类型的TypeScript泛型函数
实现精准类型推断的
getSurveyData泛型函数 需求是实现getSurveyData函数,根据输入对象的结构(顶层值支持string/object/boolean/number),精准推断返回值的具体类型,而非当前宽泛的{ [x: string]: string | boolean | number; }。
输入示例1
const MOCK_DATA = { role: { option: 'Founder / CEO', text: '', }, content: { option: 'Marketing videos', text: '', }, }; getSurveyData(MOCK_DATA) // 返回类型应为: // { // role: string; // content: string; // }
输入示例2
const MOCK_DATA2 = { position: { option: ['Founder / CEO', 'Developer'], text: '', }, termsConsent: true, }; getSurveyData(MOCK_DATA2) // 返回类型应为: // { // position: string; // termsConsent: boolean; // }
原有代码(类型推断不精准)
type FormValues = { [key: string]: | { option: string | string[]; text: string; } | boolean | string | number }; export const getSurveyData = (formValues: FormValues) => { return Object.entries(formValues).reduce( ( prev: { [key: string]: string | boolean | number; }, [key, data], ) => { let value: string | boolean | number = ''; if (data instanceof Object) { if (Array.isArray(data.option)) { value = data.option.join(', '); } else { value = data.option; } } if (typeof data === 'boolean' || typeof data === 'string' || typeof data === 'number') { value = data; } return { ...prev, [key]: value }; }, {}, ); };
修改后的泛型实现
要实现精准类型推断,需要使用泛型结合条件类型来映射输入类型到输出类型:
// 定义单个字段的输出类型映射 type SurveyFieldOutput<T> = T extends { option: infer O } ? O extends string[] ? string : O extends string ? string : never : T extends boolean | string | number ? T : never; // 定义整个对象的输出类型映射 type SurveyDataOutput<T> = { [K in keyof T]: SurveyFieldOutput<T[K]>; }; export const getSurveyData = <T extends Record<string, any>>(formValues: T): SurveyDataOutput<T> => { return Object.entries(formValues).reduce((prev, [key, data]) => { let value: SurveyFieldOutput<typeof data>; // 处理带option的对象类型 if (typeof data === 'object' && data !== null && 'option' in data) { if (Array.isArray(data.option)) { value = data.option.join(', ') as SurveyFieldOutput<typeof data>; } else { value = data.option as SurveyFieldOutput<typeof data>; } } // 处理基础类型 else if (typeof data === 'boolean' || typeof data === 'string' || typeof data === 'number') { value = data as SurveyFieldOutput<typeof data>; } // 兜底(根据需求可调整) else { value = '' as SurveyFieldOutput<typeof data>; } return { ...prev, [key]: value }; }, {} as SurveyDataOutput<T>); };
关键说明
- 泛型参数
T:捕获输入对象的具体结构,替代原有的宽泛FormValues类型,保留每个字段的精确类型信息。 - 条件类型
SurveyFieldOutput:- 若输入是带
option的对象,根据option的类型(数组或字符串),输出都映射为string(因为数组会被join转为字符串)。 - 若输入是基础类型(
boolean/string/number),直接保留原类型。
- 若输入是带
- 映射类型
SurveyDataOutput:遍历输入对象的所有键,将每个字段的类型通过SurveyFieldOutput转换为输出类型,构建最终的返回对象类型。 - 类型断言:在
reduce中使用类型断言确保TS识别prev和value的正确类型,避免类型不兼容报错。
验证效果
使用示例1的MOCK_DATA调用getSurveyData,TS会推断返回类型为{ role: string; content: string; };使用示例2的MOCK_DATA2则会推断为{ position: string; termsConsent: boolean; },完全符合需求。
内容的提问来源于stack exchange,提问作者qweezz
相关产品推荐
相关产品推荐

