装饰器的类型签名中存在一些错误,使其无法满足typechecker的要求。
为了解决这些问题,您必须了解
装饰师
和
装饰工厂
.
正如您可能怀疑的那样,decorator工厂只不过是一个返回decorator的函数。
如果要通过参数化自定义应用的装饰器,请使用装饰器工厂。
以您的代码为例,下面是一个
装饰厂
export type Constructor<T = object> = new (...args: any[]) => T;
export function AddCssClassToHost<C extends Constructor>(cssClass: string) {
return function (Class: C) {
// TypeScript does not allow decorators on class expressions so we create a local
class Decorated extends Class {
@HostBinding("class") cssClass = cssClass;
}
return Decorated;
};
}
decorator工厂接受一个参数,该参数定制它返回的decorator所使用的css,并用其替换目标(这是一个很好的例子)。
但是现在我们想重用decorator工厂来添加一些特定的css。这意味着我们需要的是一个普通的老装饰师,而不是工厂。
既然装饰厂正好归还我们所需要的东西,我们可以直接打电话给它。
使用第二个示例,
export const TopLevelRoutedComponent = AddCssClassToHost("content-container");
现在我们在应用程序中遇到错误
@TopLevelRoutedComponent
@Component({...})
export class AdminNavigationComponent {
navItems = [{nameKey: "Multisite", routerLink: "multisite"}];
}
我们必须考虑原因。
调用工厂函数将实例化其类型参数。
我们需要一个创建泛型装饰器的工厂,而不是返回非泛型装饰器的泛型装饰器工厂!
也就是说,
TopLevelRoutedComponent
需要通用。
我们可以通过简单地重写原始的decorator工厂,将类型参数移动到它返回的decorator来实现这一点
export function AddCssClassToHost(cssClass: string) {
return function <C extends Constructor>(Class: C) {
// TypeScript does not allow decorators on class expressions so we create a local
class Decorated extends Class {
@HostBinding("class") cssClass = cssClass;
}
return Decorated;
};
}
这是一个
live example