如何通过父类ModelCore构造函数为子类动态设置指定属性值?
动态过滤并赋值子类属性的泛型父类问题
需求
实现一个全局父类,让子类继承后,自动过滤服务返回的数据,只保留子类中定义的属性,开发者无需手动处理返回值。
子类示例代码
export class EnderecoMobile extends ModelCore{ id: string = '' cep: number = 1 constructor(data){ super(data) } } export class ComandadasMobile extends ModelCore { postId: number = 1 id: number = 1 name: string = "" constructor(data){ super(data) } }
当前实现的ModelCore类
export class ModelCore { constructor(data: any, canal?: string) { const device: RegExp = new RegExp(this.getDevice(), 'i'); let string = this.constructor.toString().replace(/(\n|\r)/g, ''); if (device.test(this.constructor.name)) { this.montaResposta(data, string) } } private getDevice() { const regex = /(mobile|desktop)/i; const device = this.constructor.name.match(regex); return device ? device[0] : undefined; } private montaResposta(data: any, string: string) { Object.keys(data).forEach(key => { if (typeof data[key] === 'object') this[key] = this.preencherObjeto(data[key], string); if (Array.isArray(data[key])) this[key] = this.preencherArray(data[key], string); else this.setaVariavel(data, key, string); }); } private preencherArray(data: any, string: string): any { Object.keys(data).forEach(element => { if (typeof data[element] === 'object') { this.preencherObjeto(data[element], string); } else { if (Array.isArray(data[element])) { this.preencherArray(data[element], string) } else { let key = Object.keys(data[element])[0]; this.setaVariavel(data[element], key, string); } } }) } private preencherObjeto(obj: any, string: string) { return Object.keys(obj).forEach(key => { this.setaVariavel(obj, key, string); }) } private setaVariavel(data: any, key: any, string: string) { const js: RegExp = new RegExp(` this\.${key} `); if (this.hasOwnProperty(key) || js.test(string)) { this[key] = data[key]; } else { delete data[key] } } }
测试问题
测试1:EnderecoMobile传入对象
输入数据:
{ id: '2', cep: 57057102, number: '278' }
预期结果:
{ id: '2', cep: 57057102 }
实际结果:
{ "id": "", "cep": 1 }
测试2:ComandadasMobile传入数组
输入数据:
[ { "postId": 1, "id": 1, "name": "id labore ex et quam laborum", "email": "Eliseo@gardner.biz", "body": "laudantium enim quasi est quidem magnam voluptate ipsam eos\ntempora quo necessitatibus\ndolor quam autem quasi\nreiciendis et nam sapiente accusantium" }, { "postId": 1, "id": 2, "name": "quo vero reiciendis velit similique earum", "email": "Jayne_Kuhic@sydney.com", "body": "est natus enim nihil est dolore omnis voluptatem numquam\net omnis occaecati quod ullam at\nvoluptatem error expedita pariatur\nnihil sint nostrum voluptatem reiciendis et" }, { "postId": 1, "id": 3, "name": "odio adipisci rerum aut animi", "email": "Nikita@garfield.biz", "body": "quia molestiae reprehenderit quasi aspernatur\naut expedita occaecati aliquam eveniet laudantium\nomnis quibusdam delectus saepe quia accusamus maiores nam est\ncum et ducimus et vero voluptates excepturi deleniti ratione" }, ]
实际结果:
{ "0": { "postId": 1, "id": 1, "name": "id labore ex et quam laborum" }, "1": { "postId": 1, "id": 2, "name": "quo vero reiciendis velit similique earum" }, "2": { "postId": 1, "id": 3, "name": "odio adipisci rerum aut animi" }, }
问题分析与修复方案
核心问题
- 设备判断逻辑错误:
getDevice返回匹配到的设备字符串后,用它去测试类名,导致montaResposta方法根本没执行,子类属性保持默认值。 - 正则解析类定义不可靠:通过
this.constructor.toString()解析属性的方式容易出错,且没必要。 - 数组处理逻辑错误:
preencherArray没有返回新数组,而是直接将元素挂载到实例上,导致数组变成键值对对象。 - 嵌套对象/数组未正确创建子类实例:嵌套结构没有生成对应子类的实例,无法递归过滤属性。
修复后的泛型ModelCore实现
export class ModelCore<T extends ModelCore<T>> { constructor(data?: Partial<T>) { // 如果需要保留仅处理mobile/desktop后缀类的逻辑,取消下面两行注释 // const isTargetClass = /(mobile|desktop)/i.test(this.constructor.name); // if (!data || !isTargetClass) return; if (!data) return; // 获取当前子类实例的所有属性(即子类定义的属性) const ownProps = Object.keys(this) as Array<keyof T>; for (const key of ownProps) { const value = data[key]; if (value === undefined) continue; // 处理数组:递归创建子类实例 if (Array.isArray(value)) { this[key] = value.map(item => typeof item === 'object' && item !== null ? new (this.constructor as new (data: Partial<T>) => T)(item) : item ) as T[keyof T]; } // 处理对象:递归创建子类实例 else if (typeof value === 'object' && value !== null) { this[key] = new (this.constructor as new (data: Partial<T>) => T)(value) as T[keyof T]; } // 基础类型直接赋值 else { this[key] = value as T[keyof T]; } } } }
修复说明
- 泛型支持:用
T extends ModelCore<T>约束子类类型,确保类型安全。 - 简化判断逻辑:去掉不可靠的正则解析类定义,直接通过
Object.keys(this)获取子类实例的属性,精准过滤。 - 正确处理数组/嵌套对象:数组元素和嵌套对象都会创建当前子类的实例,递归过滤属性,同时保持数组结构。
- 可配置的类过滤:如果需要仅处理带mobile/desktop后缀的类,可取消注释对应的判断代码。
测试验证
- 给
EnderecoMobile传入测试对象,会正确覆盖默认值,过滤掉number属性,得到预期结果。 - 给
ComandadasMobile传入测试数组,会返回包含ComandadasMobile实例的数组,每个实例仅保留postId、id、name属性,且保持数组结构。
内容的提问来源于stack exchange,提问作者Diego Souza
相关产品推荐
相关产品推荐

