如何为带对象与键参数的ParseErrorIntoString函数定义正确TS类型
问题描述
我需要定义一个辅助函数ParseErrorIntoString,用来解析Axios错误,并把生成的错误消息存入指定对象的指定字符串属性。期望的调用方式如下:
axios.get(...).then(...).catch(ParseErrorIntoString(myClass, 'loadError'));
其中myClass是TypeScript类实例(通常用this代替),loadError是该类的字符串类型属性。参考jest.spyOn的设计思路,要求:
- 传入非字符串属性时TypeScript能报错
- 能自动推断类型
- 解决之前遇到的
Type 'string' is not assignable to type T[StringPropertyNames<T>]类型不兼容错误
之前尝试过提取NonFunctionPropertyNames、使用Extract工具类型等方法,但要么无法传入this、自动推断失败,要么允许非字符串属性传入,或者赋值时出现类型错误。
解决方案
通过泛型约束和条件类型可以精准限制属性类型,同时确保函数能正确推断类型并完成赋值。以下是完整实现:
import type { AxiosError } from 'axios'; // 工具类型:提取对象中值为字符串类型的属性名 type StringPropertyNames<T> = { [K in keyof T]: T[K] extends string ? K : never; }[keyof T]; /** * 生成Axios错误处理函数,将解析后的错误消息存入指定对象的字符串属性 * @param target 目标对象(通常是类实例this) * @param propName 目标对象的字符串类型属性名 * @returns Axios错误处理函数 */ function ParseErrorIntoString<T extends object>( target: T, propName: StringPropertyNames<T> ): (error: unknown) => void { return (error: unknown) => { // 解析Axios错误生成字符串消息 let errorMessage = 'Unknown error'; if (error instanceof AxiosError) { errorMessage = error.response?.data?.message || error.message || errorMessage; } else if (error instanceof Error) { errorMessage = error.message; } else if (typeof error === 'string') { errorMessage = error; } // 类型断言确保赋值安全(propName已被约束为字符串属性) target[propName] = errorMessage as T[StringPropertyNames<T>]; }; }
关键说明
StringPropertyNames<T>工具类型:遍历对象所有属性,仅保留值类型为string的属性名,传入非字符串属性时TypeScript会直接报错,符合预期校验逻辑。- 泛型约束
T extends object:确保传入的target是对象类型,支持类实例(包括this)的传入。 - 返回函数类型:明确返回接收
unknown类型错误的处理函数,适配Axios的catch回调要求。 - 类型断言:由于
StringPropertyNames<T>已确保propName对应属性为字符串类型,此处断言安全,解决了类型不兼容错误。
使用示例
class MyClass { loadError = ''; // 字符串类型属性 someNumber = 0; // 非字符串属性 } const myClass = new MyClass(); axios.get('/api/data') .then(res => console.log(res)) // 正确:loadError是字符串属性 .catch(ParseErrorIntoString(myClass, 'loadError')); // 错误:Type '"someNumber"' is not assignable to type 'StringPropertyNames<MyClass>' // .catch(ParseErrorIntoString(myClass, 'someNumber'));
内容的提问来源于stack exchange,提问作者Greg Veres
相关产品推荐
相关产品推荐

