Typescript 类型,允许字段名称、自身和派生类的属性

Typescript 类型,允许字段名称、自身和派生类的属性,typescript,Typescript,假设我们有一个基类,它应该声明一个方法,该方法接受类属性之一的名称或任何派生类的属性名称作为字符串参数: export abstract class BaseClass { public someField1: number = 2; public get someProperty1(): number { return 1; } public someMethod1(): void { } // TODO: What is

假设我们有一个基类,它应该声明一个方法,该方法接受类属性之一的名称或任何派生类的属性名称作为字符串参数:

export abstract class BaseClass {
    public someField1: number = 2;

    public get someProperty1(): number {
        return 1;
    }

    public someMethod1(): void {
    }

    // TODO: What is the proper type for propertyName?
    protected method(propertyName: string): void {
        const propertyValue: any = this[propertyName];
        // ...
    }
}
我们有一些派生类,使用
method()
的测试:

export class DerivedClass extends BaseClass {
    protected someField2: number = 2;

    protected get someProperty2(): number {
        return 1;
    }

    protected someMethod2(): void {
    }

    public test(): void {
        super.method("someField1"); // Allowed
        super.method("someProperty1"); // Allowed
        super.method("someMethod1"); // Not allowed

        super.method("someField2"); // Allowed
        super.method("someProperty2"); // Allowed
        super.method("someMethod2"); // Not allowed

        super.method(""); // Not allowed
        super.method("qwerty"); // Not allowed
    }
}
这是

在上面的示例中,我使用了
string
作为
方法()的参数类型。但在这种情况下,任何字符串都可以传入,编译器无法验证它是否是现有属性的名称

另外,最好从允许的值列表中排除方法名称(
“someMethod1”
“someMethod2”


哪种类型的
propertyName
必须只允许
BaseClass
和任何派生类的字段和属性的名称?

您几乎可以实现您想要做的事情。您可以使用多态
this
类型来引用当前类(因此它将在重写类中表示派生类,在基类中表示基类)。我们还可以使用
keyof
获取类型的键(在本例中为
this
类型)

有两个限制:

  • keyof
    不返回类型的私有属性,这只适用于公共属性
  • keyof将返回所有属性。虽然可以过滤掉函数,但这在类内部不起作用(因为
    this
    本质上是一个自由类型参数,它是完全已知的,因为它可以是此类或派生类,我们需要条件类型来进行过滤,除非类型完全已知,否则无法重新求解
守则:

export abstract class BaseClass {
    public someField1: number = 2;

    public get someProperty1(): number {
        return 1;
    }

    public someMethod1(): void {
    }

    // TODO: What is the proper type for propertyName?
    protected method(propertyName: keyof this): void {
        const propertyValue: any = this[propertyName];
        // ...
    }
}

export class DerivedClass extends BaseClass {
    private someField2: number = 2;

    public get someProperty2(): number {
        return 1;
    }

    public someMethod2(): void {
    }

    public test(): void {
        super.method("someField1"); // Allowed
        super.method("someProperty1"); // Allowed
        super.method("someMethod1"); // Not allowed

        super.method("someField2"); // Allowed
        super.method("someProperty2"); // Allowed
        super.method("someMethod2"); // allowed

        super.method(""); // Not allowed
        super.method("qwerty"); // Not allowed
    }
}
过滤掉函数但仅从类外部工作的版本将使用条件类型:

type FilterFucntion<T> = { [P in keyof T]-?: T[P] extends Function ? never : P }[keyof T]
export abstract class BaseClass {
    public someField1: number = 2;

    public get someProperty1(): number {
        return 1;
    }

    public someMethod1(): void {
    }

    public method(propertyName: FilterFucntion<this>): void {
        const propertyValue: any = this[propertyName];
        // ...
    }
}

export class DerivedClass extends BaseClass {
    public someField2: number = 2;

    public get someProperty2(): number {
        return 1;
    }

    public someMethod2(): void {
    }
}
function test(): void {
    const o = new DerivedClass()
    o.method("someField1"); // Allowed
    o.method("someProperty1"); // Allowed
    o.method("someMethod1"); // Not allowed

    o.method("someField2"); // Allowed
    o.method("someProperty2"); // Allowed
    o.method("someMethod2"); // Not allowed

    o.method(""); // Not allowed
    o.method("qwerty"); // Not allowed
}
type filterFunction={[P in keyof T]-?:T[P]扩展函数?never:P}[keyof T]
导出抽象类基类{
公共字段1:编号=2;
公共获取某些属性1():编号{
返回1;
}
public someMethod1():void{
}
公共方法(propertyName:FilterFunction):无效{
常量propertyValue:any=此[propertyName];
// ...
}
}
导出类DerivedClass扩展基类{
公共字段2:编号=2;
public get someProperty2():编号{
返回1;
}
public someMethod2():void{
}
}
函数测试():void{
常量o=新的DerivedClass()
o、 方法(“someField1”);//允许
o、 方法(“someProperty1”);//允许
o、 方法(“someMethod1”);//不允许
o、 方法(“someField2”);//允许
o、 方法(“someProperty2”);//允许
o、 方法(“someMethod2”);//不允许
o、 方法(“”;//不允许
o、 方法(“qwerty”);//不允许
}