记录一次关于用typescript封装restful api碰到的问题
这是我在 learn_koa 里面遇到的一个问题.
场景复现:
我需要封装Error到一个基类上面,然后后续所有自定义的异常全部继承这个基类,以后处理业务的时候就可以争对性处理。以下是js 的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class BaseError extends Error { errorCode = 0 construct(errorCode = 0) { super() if (errorCode) { this.errorCode = errorCode; } } }
class CustomError extends BaseError { errorCode = 100001
construct(errorCode = 0) { super() if (errorCode) { this.errorCode = errorCode; } } }
function start () { try { const success = Math.random() > 0.5; if (success) { throw new CustomError(); } else { throw new Error(); } } catch (e) { if (e instanceof BaseError) { console.log('出错了!') } else { console.log('出错了!!!!') } } }
start();
|
如上,我用了一个随机数来模拟处理业务出错的情况,在碰到已知的错误时我们可以用已有的逻辑来处理,比如参数校验错误了,直接通知前端错误,请求第三方出错了,就通知系统的维护人员。本质上的核心代码就是这一句:
1
| (new CustomError()) instanceof BaseError;
|
在这里面的示例是可以返回true的,但是我在迁移到ts的时候。发现:
1
| (new CustomError()) instanceof BaseError;
|
你没有看错,是false,当然这只在tsconfig 设置 compilerOptions 打包至es5的情况下,es6不存在以上的问题,但是目前大部分项目还是要降级到es5。
那么,这是为什么呢?我们可以通过两个原型链来看看。
1
| console.log((new CustomError()).__proto__)
|
如此,我们可以清楚的看到我们自定义的对象实例的本质是Error对象,并不是BaseError, 所以我们使用instanceof的时候是false。
那,有什么办法可以改变实例后的原型链么?
其实TS官方已经给出了答案,只需要在构造函数下加入下面一句就可以了
1
| Object.setPrototypeOf(this, new.target.prototype);
|
完整实例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| class BaseError extends Error { errorCode: number = 0 construct(errorCode: number = 0) { super() Object.setPrototypeOf(this, new.target.prototype); if (errorCode) { this.errorCode = errorCode; } } }
class CustomError extends BaseError { errorCode: number = 100001
construct(errorCode: number = 0) { super() if (errorCode) { this.errorCode = errorCode; } } }
function start () { try { const success = Math.random() > 0.5; if (success) { throw new CustomError(); } else { throw new Error(); } } catch (e) { if (e instanceof BaseError) { console.log('出错了!') } else { console.log('出错了!!!!') } } }
start();
|
我曾经被这个问题困扰了很久,于是把这个记录下来,以方便后续查看。