我想构建如下所示的东西。我尝试找了很多地方,但都没有得到我想要的。
// Typescript Class or interface
export class(or interface) Person {
firstName: string;
lastName: string;
}
现在在 Angular 组件中,我想使用这样的东西:
//Assume Person type is class
let p = new Persons();
然后,当我编写 p.firstName.toPropertyName() 返回属性名称时,我想实现类似的目标。 “名” 这里 toPropertyName() 是我对对象的任何属性的扩展方法。
再次,我知道我可以使用那些 object.keys 并实现上述行为,但这并不适合我的场景。
在 c# 中,使用反射可以很容易地实现这一点,但在 typescript/javascript 中很难做到这一点。
问题是 JavaScript 中并没有像
nameof
这样的东西。不过,也有解决方法,请参阅Javascript 中的字符串形式的变量名称了解更多信息。
我尝试提出一种generic类型安全的方法,它不会自动将类属性映射到字符串,而是强制您通过类型检查返回正确的字符串。这有一个很大的优点:
toPropertyName()
返回属性名称的字符串文字类型。像 Object.keys({ someVariable })[0]
这样的东西只会给你一个任意的 string
。
另一方面,它的代码太多,对于现实世界的情况来说不太实用。我使用
get
ters 来修改属性的返回值。
type PropertyGetValue<V, T, K extends keyof T> = {
value: V;
toPropertyName: () => K;
};
class Extension<T> {
protected getPropertyGetValue<V, K extends keyof T>(
value: V,
propertyKey: K,
): PropertyGetValue<V, T, K> {
return { value, toPropertyName: () => propertyKey };
}
}
class Person extends Extension<Person> {
private _firstname: string;
private _lastname: string;
constructor(firstname: string, lastname: string) {
super();
this._firstname = firstname;
this._lastname = lastname;
}
get firstname(): PropertyGetValue<
typeof this._firstname,
Person,
"firstname"
> {
return super.getPropertyGetValue(this._firstname, "firstname");
}
set firstname(value: string) {
this._firstname = value;
}
get lastname(): PropertyGetValue<typeof this._firstname, Person, "lastname"> {
return super.getPropertyGetValue(this._lastname, "lastname");
}
set lastname(value: string) {
this._firstname = value;
}
}
const p = new Person("Jason", "Becker");
const firstname = p.firstname.value;
// ^? const firstname: string
const firstnamePropertyName = p.firstname.toPropertyName();
// ^? const firstnamePropertyName: "firstname"