这是为类的方法写的装饰器函数
function autoSave (_target: BookmarkModel, _name: string, descriptor: PropertyDescriptor): PropertyDescriptor {
const value = descriptor.value
descriptor.value = function (...args: never): boolean {
const ret = value.apply(this, args)
if (ret === true) {
this.save()
}
return ret
}
return descriptor
}
代码强行执行是完全 OK 的,但是 this.save()这行报个错:
类型“PropertyDescriptor”上不存在属性“save”。
this.save()实际就是执行类实例上的 save 方法完全没问题,但现在这样我就很懵,怎么解决
1
zhyl 2020-07-09 12:12:02 +08:00 via Android
1. 参数里指定 this 类型。
2. this 转换成 any 再调用。 |
2
rikka OP 初学 TS 瞎试一番,(this as MyClass).save(),这样就解决了,不过看起来似乎不太优雅?
|
3
oott123 2020-07-09 13:39:24 +08:00
如果你清楚自己的 this 是什么类型:
descriptor.value = function (this: YourTypeHere, ...args: never): boolean { 如果 this 和 autoSave 的上下文相同: descriptor.value = (...args: never): boolean => { |
4
optional 2020-07-09 13:43:22 +08:00
这里你用 this 干嘛,用_target 啊,_target 不就是你的 this 吗?
|
5
rabbbit 2020-07-09 13:46:09 +08:00
interface PropertyDescriptor {
save?: Function; } function autoSave(_target: BookmarkModel, _name: string, descriptor: PropertyDescriptor): PropertyDescriptor { const value = descriptor.value descriptor.value = function (...args: never): boolean { const ret = value.apply(this, args) if (this.save) { // <-- this.save(); } return ret } return descriptor } |
6
vuevue 2020-07-09 13:48:06 +08:00 via Android
函数调用时用 bind(this)试试
|
7
rikka OP @oott123 #3 `descriptor.value = function (this: YourTypeHere, ...args: never)`这么搞相当于改变原函数的参数列表,调用方法的时候还得额外传个 this 参数,不行
|
8
rikka OP @optional #4 https://es6.ruanyifeng.com/#docs/decorator
装饰器第一个参数是类的原型对象,上例是 Person.prototype,装饰器的本意是要“装饰”类的实例,但是这个时候实例还没生成,所以只能去装饰原型(这不同于类的装饰,那种情况时 target 参数指的是类本身);第二个参数是所要装饰的属性名,第三个参数是该属性的描述对象。 实测结果确实如此_target 不是 this 而是类本身 |
9
rikka OP @rabbbit #5 本来 save 就不是 PropertyDescriptor 里面的方法,强行给他加个定义,并且这样还覆盖掉原版 PropertyDescriptor,不行啊
|
10
Jirajine 2020-07-09 14:32:19 +08:00 via Android
感觉 typescript 的类型推导特别傻逼,一点都不智能。比如初始化一个空数组就给推导成[never],完全不分析后续使用的上下文。
|
11
optional 2020-07-09 14:58:03 +08:00 1
@rikka 如果你的 save 是直接由 BookmarkModel 定义的,那么它的 prototype 上就有 save 方法啊。
_target.save.call(this,args)不可以吗 |
12
oott123 2020-07-09 15:06:01 +08:00 1
@rikka #7 你确定你试过了吗
https://www.typescriptlang.org/play/index.html#code/GYVwdgxgLglg9mABAQwBRQBYwM4C5HZQBOMYA5gDQpFkCM+YIAtgEYCmRAlIgN4BQfAL5A 看右边的编译结果,this 会被编译掉,只做类型提示使用。 |
15
rabbbit 2020-07-09 17:36:43 +08:00
不一定非要覆盖 PropertyDescriptor , 你可以用 extends 扩展它.
如果 一开始不存在 save 方法, 之后可能会添加. 则要在创建时使用 ?: 表示可能存在这个属性. |
16
rikka OP @rabbbit #15 save 方法既不是,也不应该是 PropertyDescriptor 的成员,即便不覆盖扩展它也是非常不合理的做法吧
|
18
miloooz 2020-07-10 17:26:48 +08:00
第三个是官网介绍上的方法,编译会去掉 this 这个参数。官网推荐就挺好。
|