React Native升级后Jest测试报错:无法赋值只读prototype属性
问题:React Native升级至0.71.x后Jest单元测试因NetworkError原型赋值失败
报错信息
TypeError: Cannot assign to read only property 'prototype' of function 'function NetworkError(message, code) { var name = arguments.length > 2 && arguments[2] !== undefined ? argume...<omitted>... }' 19 | } 20 | } > 21 | NetworkError.prototype = Object.create(Error.prototype);
现有NetworkError代码
export class NetworkError { public message: string | null; public name: string; public code: number; constructor( message: string | null, code: number, name: string = 'NetworkError', ) { this.message = message; this.name = name; this.code = code; } } NetworkError.prototype = Object.create(Error.prototype);
当前依赖版本
"dependencies": { "react": "18.2.0", "react-native": "0.71.11" }, "devDependencies": { "@babel/core": "^7.20.0", "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", "@react-native-community/eslint-config": "^3.2.0", "@tsconfig/react-native": "^2.0.2", "@types/jest": "^29.2.1", "@types/react": "^18.0.24", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.2.1", "eslint": "^8.19.0", "jest": "^29.2.1", "metro-react-native-babel-preset": "0.73.10", "prettier": "^2.4.1", "react-test-renderer": "18.2.0", "typescript": "4.8.4" },
解决方案
方案1:改用ES6类继承Error(推荐)
直接让NetworkError继承原生Error,自动继承原型链,避免手动赋值prototype的问题:
export class NetworkError extends Error { public code: number; constructor( message: string | null, code: number, name: string = 'NetworkError', ) { super(message ?? undefined); // 调用Error构造函数传递message this.name = name; // 覆盖Error默认的name属性 this.code = code; // 修复部分环境下的原型链问题(如旧版Node.js) Object.setPrototypeOf(this, NetworkError.prototype); } }
方案2:合并原型属性而非替换整个prototype
如果因循环依赖等原因无法使用继承,可通过Object.assign将Error原型的属性合并到NetworkError原型上,而非直接替换:
export class NetworkError { public message: string | null; public name: string; public code: number; constructor( message: string | null, code: number, name: string = 'NetworkError', ) { this.message = message; this.name = name; this.code = code; } } // 合并Error原型的属性到NetworkError原型 Object.assign(NetworkError.prototype, Error.prototype); // 保留NetworkError自身的constructor属性 Object.defineProperty(NetworkError.prototype, 'constructor', { value: NetworkError, enumerable: false, });
方案3:使用Object.setPrototypeOf设置原型链
通过Object.setPrototypeOf修改原型链,替代直接赋值prototype的操作:
export class NetworkError { public message: string | null; public name: string; public code: number; constructor( message: string | null, code: number, name: string = 'NetworkError', ) { this.message = message; this.name = name; this.code = code; } } // 设置NetworkError的原型继承自Error.prototype Object.setPrototypeOf(NetworkError.prototype, Error.prototype);
原因说明
ES6类的prototype属性是只读的,直接赋值NetworkError.prototype = ...会触发TypeError。React Native 0.71+版本升级了Babel/TypeScript编译配置,严格遵循ES规范,因此旧代码中的手动替换prototype操作不再被允许。
内容的提问来源于stack exchange,提问作者dlc
相关产品推荐
相关产品推荐

