我正在编写一个装饰器,该装饰器将类实例作为参数接收,并且将需要此类的所有方法来返回它。我遇到的问题是在类实例中还有其他不符合此签名的字段(即new
或prototype
)。
我该如何解决?这就是我所拥有的:
我要使用的装饰器的用途:
@Migrates(ProductCreated)
class EventMigration {
public bar (a: Record<string, any>): ProductCreated {
// ...
}
public foo (a: Record<string, any>): ProductCreated {
// ...
}
}
装饰器定义:
interface Class<T> {
new (...args: any[]): T
}
type Foo<T, V> = {
[P in keyof T]
: T[P] extends (old: Record<string, any>) => V
? 'it works!'
: 'nope!'
}
function Migrates<T, V>(y: Class<V>) {
return (x: Foo<T, V>): void => {}
}
理论上,如果其中一种方法的签名与Foo
中定义的签名不同,则应该失败,但如果这样做,则不会出现编译错误。
答案 0 :(得分:0)
这最终是TypeScript闭包的怪异行为。如果我在返回类型中指定Migrates
的类型参数,它将起作用。
以这种方式解决:
// Required to tell the compiler that it has atleast a constructor
export interface Class<TReflected> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
new (...args: any[]): TReflected
}
// Constrains the properties to have the same type
type HomogenizePropertyTypes<Type, TPropertyType> = {
[K in keyof Type]: TPropertyType
}
// The type that we want to use for our methods
type MigrationMethod<TConcept> = (x: Record<string,any>) => TConcept
// This type constrains the properties of the first parameter to be of
// the type MigrationMethod, the return type is specified by the second parameter
type Migration<TMigration, TConcept> = HomogenizePropertyTypes<TMigration, MigrationMethod<TConcept>>
// The decorator function, it is curried, accepts a class that constrains the
// return type of the methods, and then the class that it will constrain at
// the type level. After that, we can do whatever we want with it.
function Migrates<TConcept>(
concept: Class<TConcept>
): <TMigration>(
k: Class<Migration<TMigration, TConcept>>
) => void {
return (klass) => {
return {} as any // Here we would do the rest of the stuff we want
}
}