静态方法中的 github issue 上有一个 Polymorphic this,还有一个相关的问题 here。这些正在讨论如何在静态类方法的情况下解决/解决问题。但是,在静态类成员的情况下,我找不到任何解决此问题的参考。 我们有一个模型类,这个类有一些包含映射的静态成员,其中键是模型字段。我们在继承的类中使用属性装饰器来标记模型字段(继承的类只包含字段定义)。装饰器还将字段添加到基类中定义的静态映射。请参阅下面和 playgound
中的代码function field(): any {
return function (target: Base, propertyKey: ModelFields<Base>, _descriptor: PropertyDescriptor) {
if (!target.constructor.fields) {
target.constructor.fields = {};
}
target.constructor.fields[String(propertyKey)] = String(`s_${propertyKey}`);
};
}
class Base {
['constructor']: typeof Base;
static fields: Record<string, string>;
// Actually the above is supposed to be Record<keyof ModelFields<this>, string> but 'this' is not allowed here
}
class A extends Base {
@field()
public propA: string = 'A';
}
class B extends Base {
@field()
public propB: string = 'B';
}
type ModelFields<T extends Base> = Required<Omit<T, keyof Base>>
console.log(B.fields) // B.fields type is not correct here
目前静态的 fields
被定义为 Record<string, string>
,但它并没有说明上面存在哪些键,尽管我们知道有效的键是 keyof ModelFields<this>
。但显然 this
是不允许出现的。
有没有办法让 fields
的输入正确?
答案 0 :(得分:1)
你可以做一些事情来接近你想要的效果。
您发现的第一个问题是静态成员中缺少多态 this
。我们可以用一个方法替换该字段。在一个方法上,我们可以使用泛型类型来捕获调用站点类型:
class Base {
['constructor']: typeof Base;
static fields: Record<any, any>;
static getFields<TThis extends typeof Base>(this: TThis) {
type I = InstanceType<TThis>;
return this.fields as {
[P in keyof I] : string
}
}
}
另一个问题是没有办法基于装饰器过滤成员(这些在类型系统中没有表示)。您可以做的是将品牌添加到所有具有装饰器的字段的类型中,并过滤该品牌的字段:
class Base {
['constructor']: typeof Base;
static fields: Record<any, any>;
static getFields<TThis extends typeof Base>(this: TThis) {
type I = InstanceType<TThis>;
return this.fields as {
[P in keyof I as I[P] extends FieldBrand<unknown> ? P : never] : string
}
}
}
declare const fieldBrand: unique symbol;
type FieldBrand<T> =T & { [fieldBrand]?: never }
type UnBrandField<T> = T extends FieldBrand<infer U> ? U: never;
class A extends Base {
@field()
public propA: FieldBrand<string> = 'A';
}