[英]Typescript decorators + Reflect metadata
我正在使用屬性裝飾器Field
,它將其鍵推送到fields
Reflect 元數據屬性:
export function Field(): PropertyDecorator {
return (target, key) => {
const fields = Reflect.getMetadata('fields', target) || [];
if (!fields.includes(key)) {
fields.push(key)
}
Reflect.defineMetadata('fields', fields, target)
}
}
然后我有一個抽象基類Form
來訪問 getter 附件中的元數據:
abstract class Form {
get fields() {
return Reflect.getMetadata('fields', this) || [];
}
}
到目前為止,我已經能夠成功地使用它來區分表單字段和其他類屬性。 考慮這些類:
abstract class UserForm extends Form {
@Field()
public firstName: string
@Field()
public lastName: string
get fullName() {
return this.firstName + ' ' + this.lastName;
}
}
class AdminForm extends UserForm {
@Field()
roles: string[]
}
const form = new AdminForm()
console.log(form.fields)
// ['roles', 'firstName', 'lastName']
當我為AdminForm
- MemberForm
定義一個姊妹類時會出現問題。 當Form
存在多個子類時, fields
getter 似乎返回所有字段:
class MemberForm extends UserForm {
@Field()
memberSince: Date;
}
const form = new AdminForm()
console.log(form.fields)
// ['roles', 'firstName', 'lastName', 'memberSince'] <--!!!
這對我來說毫無意義。 為什么memberSince
字段出現在AdminForm
的實例上? 如何在不同的子類上定義不同的字段?
問題是getMetadata
沿着原型鏈向下,並且將始終返回在基類型上定義的內容(因為它首先被分配)。 只有在添加新字段時,才需要使用getOwnMetadata
來獲取當前類的數組字段,並且在獲取字段時需要沿着屬性鏈向上走以獲取所有基類字段。
這應該有效:
import 'reflect-metadata'
export function Field(): PropertyDecorator {
return (target, key) => {
const fields = Reflect.getOwnMetadata('fields', target) || [];
if (!fields.includes(key)) {
fields.push(key)
}
Reflect.defineMetadata('fields', fields, target)
}
}
abstract class Form {
get fields() {
let fields = []
let target = Object.getPrototypeOf(this);
while(target != Object.prototype) {
let childFields = Reflect.getOwnMetadata('fields', target) || [];
fields.push(...childFields);
target = Object.getPrototypeOf(target);
}
return fields;
}
}
abstract class UserForm extends Form {
@Field()
public firstName!: string
@Field()
public lastName!: string
get fullName() {
return this.firstName + ' ' + this.lastName;
}
}
class AdminForm extends UserForm {
@Field()
roles!: string[]
}
const form1 = new AdminForm()
console.log(form1.fields) // ['roles', 'firstName', 'lastName']
class MemberForm extends UserForm {
@Field()
memberSince!: Date;
}
const form2 = new MemberForm()
console.log(form2.fields) // ["memberSince", "firstName", "lastName"]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.