如何在TypeScript类中包装泛型函数并保留其泛型特性?
在类中包装泛型函数并保留泛型特性
我需要在类中包装泛型函数,同时保留原函数的泛型特性,但尝试了两种写法都未能实现目标:
第一种尝试:泛型完全丢失
const func = <G extends string>(p: G) => p; class Func<A extends any[], R> { constructor(private readonly func: (...args: A) => R) {} public call(...args: A): R { return this.func(...args); } public catch(cb: (error: unknown) => void) {} // 更多方法... }
实例化后泛型信息完全丢失:
const use = new Func(func); // 类型推导为 Func<[p: any], any>
第二种尝试:实例类型保留,但调用时泛型丢失
class Func<F extends (...args: A) => R, A extends any[], R> { constructor(private readonly func: F) {} public call(...args: A): R { return this.func(...args); } public catch(cb: (error: unknown) => void) {} }
虽然实例的类型能正确关联原函数,但调用call方法时,返回类型依然是any:
use.call('str'); // 返回类型为 any
需求总结
需要一种实现方式,让类既能包装泛型函数,又能让类的方法(如call)完全保留原函数的泛型特性,欢迎任何创造性的解法。
可行解决方案
方案1:让call方法继承原函数的泛型参数
通过TypeScript的类型工具提取原函数的参数和返回类型,让call方法复用这些类型信息:
const func = <G extends string>(p: G) => p; class Func<F extends (...args: any[]) => any> { constructor(private readonly func: F) {} public call<T extends Parameters<F>[0]>(...args: Parameters<F>): ReturnType<F> { return this.func(...args) as ReturnType<F>; } public catch(cb: (error: unknown) => void) {} } const use = new Func(func); const result = use.call('str'); // result 类型为 "str",泛型特性保留
方案2:利用infer自动推导原函数类型
通过条件类型中的infer关键字,自动提取原函数的参数和返回类型,确保call方法的类型与原函数完全一致:
const func = <G extends string>(p: G) => p; class Func<F> { constructor(private readonly func: F) {} public call(...args: F extends (...args: infer A) => any ? A : never): F extends (...args: any[]) => infer R ? R : never { return this.func(...args as any); } public catch(cb: (error: unknown) => void) {} } const use = new Func(func); const result = use.call('str'); // result 类型为 "str"
方案3:直接复用原函数作为类方法
将原函数直接赋值给类的call方法,完全保留原函数的泛型签名,这是最直接的实现方式:
const func = <G extends string>(p: G) => p; class Func<F extends (...args: any[]) => any> { public call: F; constructor(func: F) { this.call = func; } public catch(cb: (error: unknown) => void) {} } const use = new Func(func); const result = use.call('str'); // result 类型为 "str"
内容的提问来源于stack exchange,提问作者Janek Eilts
相关产品推荐
相关产品推荐

