gpt4 book ai didi

typescript 装饰器 + 反射(reflect)元数据

转载 作者:行者123 更新时间:2023-12-03 23:52:42 25 4
gpt4 key购买 nike

我正在使用属性装饰器 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沿着原型(prototype)链向下,并且总是返回在基本类型上定义的内容(因为首先分配)。您需要使用 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"]

关于 typescript 装饰器 + 反射(reflect)元数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55117125/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com