如何让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
相关产品推荐
相关产品推荐

