React+TypeScript+Axios中TypeError: is not a function问题求助
问题:Axios返回数据无法实例化为Class对象,调用方法时报错
通过Axios从后端获取的数据未被正确实例化为Class类对象,调用类方法时出现Uncaught TypeError TypeError: object.method is not a function错误。
示例代码
父组件(获取数据并传递给子组件)
// imports const Component: React.FC<ComponentProps> = () => { const { id } = useParams<{ id: string }>(); const [object, setObject] = useState<Class>(new Class()); useEffect(() => { (async () => { try { const object = await Service.getById(id); setObject(object); } catch (err) { //error handling } finally { cleanup(); } })(); return () => { // cleanup }; }); return ( <Container title={object.name}> <Child object={object} /> </Container> ); }; export default Component;
子组件(调用类方法触发错误)
// imports interface Interface { object: Class; } const Child: React.FC<Interface> = ({ object }) => { object.callSomeFunction(); // 此处触发错误 return ( <SomeJSXCode /> ); }; export default Child;
Class类定义(临时用静态from方法,但不适用于多属性类)
export class Class { id: string = ''; name: string = ''; callSomeFunction = () => { // do something; } static from(object: Class): Class { const newInstance = new Class(); newInstance.id = object.id; newInstance.name = object.name; // 要是类有很多属性,这种写法太繁琐 return newInstance; } }
Service服务代码
// imports const URL = 'http://localhost:8000'; const baseConfig: AxiosRequestConfig = { baseURL: URL, headers: { 'Content-Type': 'application/json' }, withCredentials: true, }; export const backend = axios.create({ ...baseConfig, baseURL: URL + '/someEndpoint', }); export const Service = { async getById(id: string): Promise<Class> { try { const { data } = await backend.get<Class>(`/${id}`); return data; } catch (err) { throw new Error(err.response.data.message); } }, };
解决方案
核心原因
Axios返回的data只是一个普通JavaScript对象,虽然TypeScript通过类型断言标记为Class,但它并没有被实例化,自然没有Class实例的方法属性(包括类里定义的箭头函数属性,这类属性只有通过new Class()创建的实例才会拥有)。
优化方案(替代手动赋值的from方法)
方案1:改造构造函数实现批量赋值
修改Class的构造函数,让它可以接收普通对象并批量赋值:
export class Class { id: string = ''; name: string = ''; constructor(obj?: Partial<Class>) { if (obj) { Object.assign(this, obj); } } callSomeFunction = () => { // do something; } }
然后在Service中返回数据时实例化Class:
async getById(id: string): Promise<Class> { try { const { data } = await backend.get(`/${id}`); return new Class(data); // 用返回的数据实例化Class } catch (err) { throw new Error(err.response.data.message); } }
方案2:优化静态from方法支持批量赋值
如果不想修改构造函数,直接升级静态from方法:
export class Class { id: string = ''; name: string = ''; callSomeFunction = () => { // do something; } static from(obj: Partial<Class>): Class { const instance = new Class(); Object.assign(instance, obj); return instance; } }
在Service中调用该静态方法:
async getById(id: string): Promise<Class> { try { const { data } = await backend.get(`/${id}`); return Class.from(data); } catch (err) { throw new Error(err.response.data.message); } }
注意事项
- 不要依赖TypeScript的类型断言来“伪装”实例类型,类型断言仅作用于编译时检查,不会改变运行时对象的本质。
- 如果Class包含嵌套的自定义类对象,
Object.assign只会做浅拷贝,需要在构造函数或from方法中手动处理嵌套对象的实例化。
内容的提问来源于stack exchange,提问作者Lucas Pedroso Santos
相关产品推荐
相关产品推荐

