如何在TypeScript中返回保留接口的类并实现可调用?
解决方案
1. 核心思路:复用变量名+类型别名
通过TypeScript的InstanceType工具类型,我们可以直接从构造函数值中提取实例类型,无需额外的下划线命名或重复定义类结构。同时优化wrap函数的类型定义,确保运行时和类型检查都正常工作。
完整实现代码
// 实现wrap函数:运行时用Proxy让构造函数可直接调用,类型上保留原构造函数类型 function wrap<T extends new (...args: any[]) => any>(ctor: T): T { return new Proxy(ctor, { apply(target, _, args) { return new target(...args); } }) as T; } // 定义类并包装,同时创建同名类型别名指向实例类型 const Foo = wrap(class { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } }); type Foo = InstanceType<typeof Foo>; // 两种调用方式均正常,类型检查通过 const foo1: Foo = new Foo(1, 2); const foo2: Foo = Foo(3, 4);
方案优势
- 无需
_Foo这类不美观的命名,类表达式可直接匿名定义 - 类直接在
wrap函数内部定义,无需提前暴露到外部上下文 - 仅需两次
Foo命名(变量名和类型别名),大幅减少重复
2. 支持类内部自引用的写法
如果需要在类内部使用自身类型,可以给类表达式添加内部名称,同时类型别名依然复用外部变量名:
function wrap<T extends new (...args: any[]) => any>(ctor: T): T { return new Proxy(ctor, { apply(target, _, args) { return new target(...args); } }) as T; } const Foo = wrap(class Foo { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } // 类内部可直接用Foo作为实例类型 clone(): Foo { return new Foo(this.x, this.y); } }); type Foo = InstanceType<typeof Foo>; const foo: Foo = Foo(1, 2); console.log(foo.clone()); // 类型检查正常
3. 简化类型别名的通用技巧
如果觉得InstanceType<typeof Foo>写法冗余,可以定义一个通用类型别名复用:
type Instance<T> = T extends new (...args: any[]) => infer R ? R : never; // 后续只需写: type Foo = Instance<typeof Foo>;
内容的提问来源于stack exchange,提问作者user29889977
相关产品推荐
相关产品推荐

