TypeScript:无法解析通用 class 装饰器的签名
TypeScript: failure to resolve signature of generic class decorator
我无法理解为什么 TypeScript 在这种情况下需要 Child2
和 Child3
的显式泛型类型定义:
abstract class Base {
public static A: string = "Fallback_A";
public DoSmthWithClassName(): string {
return "Fallback_DoSmth";
}
constructor(...args: any[]); // overload for type consistency with children
constructor(x: string)
{ }
}
// typeof any non-abstract child of Base
type BaseType = typeof Base & (new(...args: any[]) => Base);
// decorator, modifies methods and static properties
function ClassDecorator<T extends BaseType>(valueA: string): (value: T) => T {
return (value: T) => {
value.prototype.DoSmthWithClassName = () => value.name + ".DoSmth." + value.A;
value.A = value.name + valueA;
return value;
}
}
@ClassDecorator("Foo") // OK
class Child0 extends Base {
}
@ClassDecorator("Foo") // OK
class Child1 extends Base {
constructor(x: number) {
super(x.toString());
}
}
@ClassDecorator("Foo") // Unable to resolve...
class Child2 extends Base {
static X: number = 0;
}
@ClassDecorator<typeof Child3>("Foo") // OK
class Child3 extends Base {
static X: number = 0;
}
问题是 TS 无法从唯一的参数 valueA
推断出 T 的类型。您想要的是 inner/returned 函数的通用参数:
// decorator, modifies methods and static properties
function ClassDecorator(valueA: string) {
return function <T extends BaseType>(value: T): T {
value.prototype.DoSmthWithClassName = () => value.name + ".DoSmth." + value.A;
value.A = value.name + valueA;
return value;
}
}
您的版本不会导致 Child0 和 Child1 出现任何问题,因为它们在结构上与 base 相同。
来不及回答了,不知道是否还符合需求。但是,不需要 ClassDecorator 中的通用参数,您仍然可以在其中使用 'static X' 实例化 Child2 并通过 Child2.X
.
访问 X
这是因为没有构造函数的 ClassDecorator 就像没有船的经验丰富的水手,它需要一个类型,以便 Typescript 可以确定将其编译为函数。
最好的解决方案是在 ClassDecorator 之后反映它,
const Reflected = (value:string) : ClassDecorator => {
return reflected => {
// `reflected` here is `Type<Foo>`, not `Foo`
console.log(`The reflected: ${reflected}`)
};
};
您可以立即使用它,因为 @Reflected("Foo") 不是新实例,
//@ClassDecorator("Foo") // Unable to resolve...
@Reflected("Foo")
class Child2 extends Base {
public static X: number = 0;
}
我能想到的一些原因:
- A class,基本上是 运行 时的 javascript 函数,太通用了,但常量实例不是(专注于类型),这就是为什么我们需要一个'dependency injection' 和其他好处的 ClassDecorator。
-在 Typescript 中,我们需要一种 'decorated' 实例,而不是设计时的实例本身,它在编译时提供正确的类型。
PS:如果您使用的是 'reflect-metadata' 包,您可以使用 console.log(Reflect.getMetadata('design:paramtypes', reflected));
进一步了解
我还没有看到任何副作用,如果发现任何副作用,我会更新。
我无法理解为什么 TypeScript 在这种情况下需要 Child2
和 Child3
的显式泛型类型定义:
abstract class Base {
public static A: string = "Fallback_A";
public DoSmthWithClassName(): string {
return "Fallback_DoSmth";
}
constructor(...args: any[]); // overload for type consistency with children
constructor(x: string)
{ }
}
// typeof any non-abstract child of Base
type BaseType = typeof Base & (new(...args: any[]) => Base);
// decorator, modifies methods and static properties
function ClassDecorator<T extends BaseType>(valueA: string): (value: T) => T {
return (value: T) => {
value.prototype.DoSmthWithClassName = () => value.name + ".DoSmth." + value.A;
value.A = value.name + valueA;
return value;
}
}
@ClassDecorator("Foo") // OK
class Child0 extends Base {
}
@ClassDecorator("Foo") // OK
class Child1 extends Base {
constructor(x: number) {
super(x.toString());
}
}
@ClassDecorator("Foo") // Unable to resolve...
class Child2 extends Base {
static X: number = 0;
}
@ClassDecorator<typeof Child3>("Foo") // OK
class Child3 extends Base {
static X: number = 0;
}
问题是 TS 无法从唯一的参数 valueA
推断出 T 的类型。您想要的是 inner/returned 函数的通用参数:
// decorator, modifies methods and static properties
function ClassDecorator(valueA: string) {
return function <T extends BaseType>(value: T): T {
value.prototype.DoSmthWithClassName = () => value.name + ".DoSmth." + value.A;
value.A = value.name + valueA;
return value;
}
}
您的版本不会导致 Child0 和 Child1 出现任何问题,因为它们在结构上与 base 相同。
来不及回答了,不知道是否还符合需求。但是,不需要 ClassDecorator 中的通用参数,您仍然可以在其中使用 'static X' 实例化 Child2 并通过 Child2.X
.
这是因为没有构造函数的 ClassDecorator 就像没有船的经验丰富的水手,它需要一个类型,以便 Typescript 可以确定将其编译为函数。
最好的解决方案是在 ClassDecorator 之后反映它,
const Reflected = (value:string) : ClassDecorator => {
return reflected => {
// `reflected` here is `Type<Foo>`, not `Foo`
console.log(`The reflected: ${reflected}`)
};
};
您可以立即使用它,因为 @Reflected("Foo") 不是新实例,
//@ClassDecorator("Foo") // Unable to resolve...
@Reflected("Foo")
class Child2 extends Base {
public static X: number = 0;
}
我能想到的一些原因:
- A class,基本上是 运行 时的 javascript 函数,太通用了,但常量实例不是(专注于类型),这就是为什么我们需要一个'dependency injection' 和其他好处的 ClassDecorator。 -在 Typescript 中,我们需要一种 'decorated' 实例,而不是设计时的实例本身,它在编译时提供正确的类型。
PS:如果您使用的是 'reflect-metadata' 包,您可以使用 console.log(Reflect.getMetadata('design:paramtypes', reflected));
进一步了解
我还没有看到任何副作用,如果发现任何副作用,我会更新。