为何structuredClone()会忽略AxiosError对象的子属性?
问题:structuredClone克隆AxiosError时子类属性丢失
在TypeScript Web项目中,使用structuredClone深度克隆Axios的AxiosError对象时,发现父类Error的属性(如name)被正常克隆,但AxiosError自身的属性(如isAxiosError)丢失了。
AxiosError的类型定义如下:
export interface AxiosError<T = any> extends Error { //... isAxiosError: boolean; toJSON: () => object; } interface Error { name: string; // ... }
测试代码:
function f(axiosError: AxiosError<ArrayBuffer>): void { const copy = window.structuredClone(axiosError); const a = typeof axiosError.name === "undefined"; // false const b = typeof axiosError.isAxiosError === "undefined"; // false const c = typeof copy.name === "undefined"; // false const d = typeof copy.isAxiosError === "undefined"; // true }
该问题在Firefox和Chrome中均可复现。
原因分析
这是因为structuredClone的克隆规则只针对内置可结构化克隆类型和对象的自有可枚举属性,但Axios实现AxiosError时,将isAxiosError这类子类属性定义在了原型链上,而非对象自身的自有属性。
Error的name属于实例的自有属性,且是内置类型的标准化属性,所以能被structuredClone正确复制。- 而
isAxiosError挂载在AxiosError的原型对象上,structuredClone不会遍历克隆原型链上的属性,仅克隆对象自身的自有可枚举属性,因此克隆后的对象中不存在该属性。
另外,structuredClone处理自定义对象时,只会创建普通Object实例并复制自有属性,不会保留原对象的类原型链,这也是原型属性无法被复制的核心原因。
如果需要完整克隆AxiosError,可以用以下两种方式:
- 手动复制属性并保留原型链
const copy = Object.assign(Object.create(Object.getPrototypeOf(axiosError)), axiosError);
- 利用Axios的toJSON方法重构实例
const errorJson = axiosError.toJSON(); const copy = Object.assign(new Error(), errorJson) as AxiosError<ArrayBuffer>; copy.isAxiosError = true; // 手动补充原型链上的属性
内容的提问来源于stack exchange,提问作者Marco Eckstein
相关产品推荐
相关产品推荐

