You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript父类装饰器字段未加入INCLUDED_FIELDS问题求助

问题根源分析

你遇到的问题核心在于父类的包含字段没有被子类实例继承读取:
当你在Base类的name属性上使用@JsonInclude装饰器时,该字段被添加到了以"Base"为键的INCLUDED_FIELDS映射条目里。但当实例化Staff子类时,this.constructor.name返回的是"Staff",所以原toJSON方法只会读取"Staff"对应的字段列表,完全忽略了父类Base中定义的包含字段,导致name没有被加入最终的JSON对象。

另外,虽然你的装饰器实现对于实例属性的目标对象处理是正确的(target是类的原型,target.constructor指向类本身),但缺少了原型链字段合并的逻辑,这是关键遗漏点。

解决方案

修改Base类的toJSON方法,遍历实例的原型链,收集所有父类(包括当前类)的包含字段,再统一过滤属性。同时优化装饰器的命名可读性:

// base.ts 修改后的代码
export const INCLUDED_FIELDS = new Map<string, string[]>();
export function JsonInclude(target: any, propertyKey: string){
  // 获取当前属性所属的类构造函数
  const cls = target.constructor;
  const clsName = cls.name;
  let list: string[];
  if (INCLUDED_FIELDS.has(clsName)) {
    list = INCLUDED_FIELDS.get(clsName)!;
  } else {
    list = [];
    INCLUDED_FIELDS.set(clsName, list);
  }
  list.push(propertyKey);
}
export default class Base{
  @JsonInclude
  public name: string;

  // 补充构造函数初始化name,避免字段未定义
  constructor(name: string) {
    this.name = name;
  }

  toJSON(): { [name: string]: any } {
    const json: { [name: string]: any } = {};
    const includedFields = new Set<string>();
    
    // 遍历原型链,收集所有继承层级的包含字段
    let currentProto = Object.getPrototypeOf(this);
    while (currentProto !== null) {
      const clsName = currentProto.constructor.name;
      const fields = INCLUDED_FIELDS.get(clsName);
      if (fields) {
        fields.forEach(field => includedFields.add(field));
      }
      currentProto = Object.getPrototypeOf(currentProto);
    }

    // 过滤并添加符合条件的属性
    Object.getOwnPropertyNames(this)
      .filter(name => includedFields.has(name))
      .forEach(name => {
        json[name] = this[name];
      });
    return json;
  }
}

staff.ts可以保持原样,补充构造函数调用父类初始化:

// staff.ts
import Base, { JsonInclude } from './base';

export default class Staff extends Base {
  @JsonInclude
  public salary: number = 1000;
  @JsonInclude
  public level: number = 1;
  @JsonInclude
  public comment:string = "";

  constructor(name: string) {
    super(name);
  }
}
测试验证

执行以下代码:

const staff = new Staff("Alice");
console.log(JSON.stringify(staff));

会输出预期结果:

{"name":"Alice","salary":1000,"level":1,"comment":""}
额外优化说明
  • 使用Set存储字段,避免父类和子类出现同名字段时重复添加
  • 遍历原型链的逻辑支持多层继承场景,不管继承多少层级都能正确收集所有父类的包含字段
  • 补充构造函数初始化,避免name字段出现undefined

内容的提问来源于stack exchange,提问作者armnotstrong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 17:57:28