Typescript:自引用静态类成员

标签 typescript typescript-generics

有一个github issuePolymorphic 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对吗?

最佳答案

您可以采取一些措施来更接近您想要的效果。

您发现的第一个问题是静态成员中缺乏多态 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
        }
    }
}

Playground Link

另一个问题是无法根据装饰器过滤成员(这些成员未在类型系统中表示)。您可以做的是将品牌添加到具有装饰器的所有字段的类型中,并过滤该品牌的字段:


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';
}

Playground Link

关于Typescript:自引用静态类成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65942235/

相关文章:

typescript - 使用默认数组迭代器实现 Iterable 接口(interface)

typescript - 如何为通用可选函数参数获得正确的类型推断?

Javascript/ typescript 循环一次处理数组中的一个命令

typescript - 在 Visual Studio 2015 CTP6 + TypeScript 1.4 中使用外部模块

javascript - Angular2 和 ng2Material

javascript - 以编程方式垂直调整 div 的大小

来自不同文件的 html View 中的 Angular 5 和枚举

reactjs - 根据对象中键的值定义类型

typescript - 是否可以在 Typescript 中获取记录值的数组类型?

Typescript - isEmpty 函数的通用类型保护