我试图用装饰器来装饰一个类(a-la角样式),并向它添加方法和属性。
这是我的示例装饰类:
@decorator
class Person{
}
这位是装饰师:
const decorator = (target)=>{
return class New_Class extends target {
myProp:string
}
}
但是myProp
并不是一个已知的人的财产:
person.myProp //Error - myProp does not exist on type Person
如何装饰一个打字本类并保存类型完成、类型安全等?
发布于 2019-02-27 02:52:21
发布于 2019-04-04 08:16:54
我找到了一种实现多种遗产的解决方案(实际上是对它的级联),但值得一看。
假设您有一个具有以下属性和方法的类库:
class Base {
tableName = 'My table name';
hello(name) {
return `hello ${name}`;
}
}
您需要一个类来扩展Base,但是您也定义了一些要重用的属性。为此,将执行以下功能:
type Constructor<T = {}> = new (...args: any[]) => T;
function UserFields<TBase extends Constructor>(Base: TBase) {
return class extends Base {
name: string;
email: string;
};
}
现在,我们可以做一个扩展Base和扩展UserFields的类,类型记录语言服务将从这两个类中找到属性。它模仿多个传统,但它实际上是一个级联。
class User extends UserFields(Base) { }
const u = new User();
u.tableName = 'users'; // ok
u.name = 'John'; // ok
通过这种方式,您可以在任何其他类中重用UserFields函数。这方面的一个明确示例是,如果您希望将客户端的用户对象公开为“干净”对象,并且有可用的字段,那么您就有一个连接到数据库的UserDb对象,而任何其他服务器端方法也可以具有相同的字段。我们只定义了一次数据库字段!
另一件好事是,您可以将mixin1(mixin2.(Base))链接起来,以便在同一个类中拥有尽可能多的属性。
每个人都希望装饰者的属性可以通过类型记录来显示,但同时也是一个很好的解决方案。
发布于 2019-02-26 11:13:29
有一个有很多讨论的关于这一点的GitHub问题。我认为它的总结是:装饰师不会改变class
的类型(大部分讨论是关于它是否应该这样做),因此您不能按照您想要的方式来做,如下所示:
const decorator = (target: new (...args: any) => any) => {
// note I'm extending target, not Person, otherwise you're not
// decorating the passed-in thing
return class New_Class extends target {
myProp!: string
}
}
@decorator
class Person {
noKnowledgeOfMyProp: this['myProp'] = "oops"; // error
}
declare const p: Person;
p.myProp; // error, uh oh
您可以做的只是使用您的装饰器作为一个普通的混和函数,并让Person
扩展该函数的返回值。你最终会有两个类的定义。一个是传递给decorator
的,另一个是你的新类扩展的。“内部”类(传递给decorator()
)仍然不知道添加的道具,但是“外部”类知道:
class Person extends decorator(class {
innerProp: string = "inner";
noKnowledgeOfMyProp: this['myProp'] = "oops"; // error
}) {
outerProp: string = "outer"
hasKnowledgeOrMyProp: this['myProp'] = "okay"; // okay
}
declare const p: Person;
p.myProp; // okay
这有用吗?祝好运!
https://stackoverflow.com/questions/54892401
复制