type Constructor = new (...args: any[]) => {};
function LogTime<T extends Constructor>(target: T) {
return class extends target {
createTime: Date;
constructor(...args: any[]) {
super(...args);
this.createTime = new Date();
}
getCreateTime() {
return `该对象的创建时间是:${this.createTime}`;
}
};
}
@LogTime
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
interface Person {
getCreateTime(): void;
}
const person = new Person("小明", 18);
console.log(person.getCreateTime());
class NewPerson implements Person {
name: string;
age: number;
createTime: Date;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
this.createTime = new Date();
}
getCreateTime() {
return `该对象的创建时间是:${this.createTime}`;
}
}
![]() |
1
X0V0X 23 小时 12 分钟前
这就是人们说的 java 味吗
|
![]() |
2
FrankFang128 23 小时 6 分钟前
大部分 JSer 不用装饰器
|
3
jackge0323 22 小时 35 分钟前
这部分可以跳过,基本不用。
|
![]() |
4
sjhhjx0122 22 小时 32 分钟前
这种情况还是继承比较好,当然类装饰器也可以规定类长什么样子,这样就可以要求强制继承一个带这个方法的类了
|
![]() |
5
lisongeee 22 小时 15 分钟前 ![]() ts 认为装饰器不会改变类型,因此你声明的时候类型是啥它就是啥
达到你想要的效果也很简单,将声明改为调用 const Person = LogTime( class { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } }, ); |
![]() |
6
lanten 20 小时 42 分钟前
目前再 TS 中的任何装饰器(类/方法/属性/参数装饰器)都无法更改调用该装饰器目标的原始类型.
由于你的 getCreateTime 方法是在装饰器中添加的, 且在原始类(Person)中没有该方法的签名, 所以 person 实例在类型系统中压根没有 getCreateTime 方法, 报错符合预期. 声明 `interface Person` 是不完美的, 这会破坏类型系统的准确性. (但也不是不行) 我个人认为你这种场景应该使用基类派生(extends), 而不是装饰器, 通常类装饰器需要配合方法装饰器或属性装饰器才能体现其价值 |
![]() |
7
DreamingCTW OP |
![]() |
8
DreamingCTW OP @sjhhjx0122 #4 他假设的场景是,为每一个 class 的实例对象创建时都记录一个创建时间,所以用了装饰器,这样可以很方便的为每一个 class 上写 @LogTime ,只是我在学习的过程中发现了有这个问题。
|
![]() |
9
sillydaddy 17 小时 35 分钟前
可以给装饰器定义明确的返回类型:
``` interface WithCreateTime { getCreateTime(): string; } function LogTime<T extends Constructor>(Base: T): T & Constructor<WithCreateTime>; ``` 上面的 LogTime 函数定义中,明确指定了返回类型:T & Constructor<WithCreateTime> 。并且与 LogTime 实际返回值的类型是一致的。 |