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

如何让TypeScript的Wrapper类实例兼具Wrapper与泛型T类型?

解决方法

要让Wrapper<T>自动兼具自身类方法和被包装对象T的属性,无需手动声明交叉类型,可通过以下两种方案实现:

方案一:类型别名交叉(推荐,类型精确)

先定义内部类实现核心逻辑,再通过类型别名将其与T交叉,同时调整构造函数返回类型,让实例自动成为交叉类型:

// 内部类,实现Wrapper的核心方法
class _Wrapper<T extends object> {
  constructor(private readonly target: T) {
    // 将被包装对象的属性拷贝到实例,确保运行时可访问
    Object.assign(this, target);
  }

  // 自定义额外方法
  extraMethod(): void {
    console.log("执行额外方法,目标对象:", this.target);
  }
}

// 类型别名自动交叉_Wrapper<T>与T
type Wrapper<T extends object> = _Wrapper<T> & T;

// 调整构造函数类型,让new Wrapper(...)返回Wrapper<T>
const Wrapper: new <T extends object>(target: T) => Wrapper<T> = _Wrapper as any;

// 使用示例
const wrapped = new Wrapper({ a: 100, b: "test" });
wrapped.a; // 直接访问T的属性,类型为number
wrapped.b; // 类型为string
wrapped.extraMethod(); // 调用Wrapper的方法

方案二:类实现索引签名(简单但类型精度略低)

如果不想拆分内部类,可在Wrapper类中添加索引签名,让TypeScript允许访问T的属性,同时在构造函数中拷贝属性到实例:

class Wrapper<T extends object> {
  // 索引签名兼容T的所有属性
  [K in keyof T]: T[K];

  constructor(target: T) {
    Object.assign(this, target);
  }

  extraMethod(): void {
    console.log("执行额外方法");
  }
}

// 使用示例
const wrapped = new Wrapper({ a: 200 });
wrapped.a; // 正常访问,类型为number
wrapped.extraMethod(); // 正常调用

补充:Proxy优化运行时

如果不想拷贝属性,可通过Proxy拦截属性访问,运行时更高效,类型上仍用方案一的类型别名:

class _Wrapper<T extends object> {
  constructor(private readonly target: T) {
    return new Proxy(this, {
      get(_, prop) {
        // 优先访问Wrapper自身方法,再转发到目标对象
        if (prop in _) return _[prop as keyof _Wrapper<T>];
        return (target as any)[prop];
      }
    });
  }

  extraMethod(): void {
    console.log("执行额外方法,目标对象:", this.target);
  }
}

type Wrapper<T extends object> = _Wrapper<T> & T;
const Wrapper: new <T extends object>(target: T) => Wrapper<T> = _Wrapper as any;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 19:35:28