假设我们有一个基类,该基类应该声明一个方法,该方法接受类属性之一的名称或任何派生类的属性名称作为字符串参数:
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
}
}
这里是Playground。
在上面的示例中,我使用string
作为method()
参数的类型。但是在这种情况下,任何字符串都可以传入,并且编译器无法验证它是否是现有属性的名称。
此外,最好从允许值列表中排除方法名称("someMethod1"
,"someMethod2"
)。
propertyName
应该只允许使用哪种类型的字段BaseClass
和任何派生类的名称?
答案 0 :(得分:1)
您几乎可以实现您想做的事情。您可以使用多态this
类型来引用当前类(这样它将代表redrived类中的派生类和基类中的基类)。我们还可以使用keyof
获取一种类型的键(在这种情况下为this
类型)。
有两个限制:
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
}