rot*_*emx 9 typescript ecmascript-6 es6-class typescript-decorator typescript-class
我正在尝试使用装饰器(a-la-angular样式)装饰一个类,并向其添加方法和属性。
这是我的装饰类示例:
@decorator
class Person{
}
Run Code Online (Sandbox Code Playgroud)
这是装饰器:
const decorator = (target)=>{
return class New_Class extends target {
myProp:string
}
}
Run Code Online (Sandbox Code Playgroud)
但myProp不是 Person 的已知属性:
person.myProp //Error - myProp does not exist on type Person
Run Code Online (Sandbox Code Playgroud)
如何装饰打字稿类并保留类型完成、类型安全等?
GitHub上有一个关于此问题的问题,有很多讨论。我认为它的总结是:装饰器不会改变a 的类型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
Run Code Online (Sandbox Code Playgroud)
相反,您可以做的就是使用装饰器作为普通mixin函数,并Person扩展其返回值。您最终有两个类定义...一个是传递进去的decorator,另一个是您的新类扩展的。“内部”类(传递给decorator())仍然不知道添加的 props,但“外部”类知道:
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
Run Code Online (Sandbox Code Playgroud)
这有帮助吗?祝你好运!
为了补充jcalz response,回到装饰模式的定义,它不会改变其目标的接口/合同。这不仅仅是术语。TypeScript 装饰器与 Java 注释和 .NET 属性有相似之处,它们与不更改接口的事实一致:它们只是添加元数据。
类 mixin 是解决您问题的好选择。但最好不要在其名称中使用“装饰者”以避免混淆。
我找到了一个解决方案来实现某种多重遗产(真正级联它),但值得一看。
假设您有一个 Base 类,其中包含一些属性和方法:
class Base {
tableName = 'My table name';
hello(name) {
return `hello ${name}`;
}
}
Run Code Online (Sandbox Code Playgroud)
并且您想要一个类来扩展 Base 但您还定义了一些要重用的属性。为此将执行以下功能:
type Constructor<T = {}> = new (...args: any[]) => T;
function UserFields<TBase extends Constructor>(Base: TBase) {
return class extends Base {
name: string;
email: string;
};
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以做一个扩展 Base 并扩展 UserFields 的类,打字稿语言服务将从这两个类中找到属性。它模仿了多重遗产,但它实际上是一个级联。
class User extends UserFields(Base) { }
const u = new User();
u.tableName = 'users'; // ok
u.name = 'John'; // ok
Run Code Online (Sandbox Code Playgroud)
通过这种方式,您可以将 UserFields 函数与任何其他类重用。一个明显的例子是,如果您想将客户端的 User 对象公开为“干净”对象并拥有可用的字段,然后您有一个连接到数据库的 UserDb 对象,并且任何其他服务器端方法都可以具有相同的字段也。我们只定义数据库字段一次!
另一个好处是你可以链接mixin mixin1(mixin2....(Base)) 以在同一个类中拥有尽可能多的属性。
每个人都希望通过打字稿可以看到装饰器属性,但同时也是一个很好的解决方案。
| 归档时间: |
|
| 查看次数: |
5578 次 |
| 最近记录: |