Typescript 采用扩展基类型的构造函数并返回减去第一个参数的同一构造函数的函数

Typescript 采用扩展基类型的构造函数并返回减去第一个参数的同一构造函数的函数,typescript,generics,Typescript,Generics,我正在将旧的JS代码库转换为TypeScript。我有一个相当高级的场景,我不知道如何正确分配类型。如果可能的话,我想避免使用任何类型的方法 首先,我有一个建立公共上下文的基类,然后有几十个扩展这个基类的类: 类上下文{} 类上下文相关{ 受保护的只读上下文:上下文; 构造函数上下文:上下文{ this.context=上下文; } } 类MyClass扩展了与上下文相关的{ 私有myParam:string; constructorcontext:Context,myParam:string{

我正在将旧的JS代码库转换为TypeScript。我有一个相当高级的场景,我不知道如何正确分配类型。如果可能的话,我想避免使用任何类型的方法

首先,我有一个建立公共上下文的基类,然后有几十个扩展这个基类的类:

类上下文{} 类上下文相关{ 受保护的只读上下文:上下文; 构造函数上下文:上下文{ this.context=上下文; } } 类MyClass扩展了与上下文相关的{ 私有myParam:string; constructorcontext:Context,myParam:string{ 超级上下文; this.myParam=myParam; } } 值得一提的是,按照惯例,所有扩展这个基类的类都将上下文作为它们的第一个参数

我需要将其中一些类公开给一个面向公共的API,但是不能通过公共API访问上下文参数,因此我通过绑定第一个构造函数参数来公开它们:

函数bindClasscontext,类{ //奇迹发生了 //这是一个非常简单的例子。 //实际逻辑要复杂得多,以便保留检查实例等 返回Class.bind{},context; } 函数getPublicApicontext{ 返回{ MyClass:bindClasscontext,MyClass, } } 这个系统工作得非常好,但我现在正试图找出如何将其转换为TypeScript,如果可能的话

我尝试了几次迭代,最接近我的想法是:

函数bindClasscontext:Context,类:new Context:Context=>T:new=>T{ //奇迹发生了 } 但这当然行不通。当接受类型声明时,约束将拒绝接受上下文相关的子类,这些子类接受的内容超过上下文参数:

bindClasscontext,MyClass; /* 错误: 类型为“typeof MyClass”的参数不能分配给类型为“new context:context=>MyClass”的参数。 构造签名的类型不兼容。 类型“new context:context,myParam:string=>MyClass”不可分配给类型“new context:context=>MyClass”。ts2345 */ 我理解为什么这不起作用,但我找不到一个完全符合我所寻找的解决方案。是否有某种方法可以动态地包含附加参数,然后再包含它们,例如:

函数bindClasscontext:上下文,类:新上下文:上下文,…args:unknown[]=>T:new…args:[未知]=>T{ //奇迹发生了 } /* 错误: 类型为“typeof MyClass”的参数不能分配给类型为“new context:context,…args:unknown[]=>MyClass”的参数。 构造签名的类型不兼容。 类型“new context:context,myParam:string=>MyClass”不可分配给类型“new context:context,…args:unknown[]=>MyClass”。 参数“myParam”和“args”的类型不兼容。 类型“未知”不可分配给类型“字符串”。ts2345 */
我不确定是否有真正的动态解决方案,但可以使用重载和泛型来允许使用类型匹配的附加参数

缺点是,您必须为每个附加参数包含一个重载,这意味着您不能允许无限数量的参数

但是,提供足够的重载以满足您自己的代码库需求并不困难:

函数bindClasscontext:Context,类:newcontext:Context=>T:new=>T; 函数bindClasscontext:Context,类:新上下文:Context,…args:[T1]=>T:new…args:[T1]=>T; 函数bindClasscontext:Context,Class:newcontext:Context,…args:[T1,T2]=>T:new…args:[T1,T2]=>T; 函数bindClasscontext:Context,Class:newcontext:Context,…args:[T1,T2,T3]=>T:new…args:[T1,T2,T3]=>T; 函数bindClasscontext:Context,类:新上下文:Context,…args:[T1?,T2?,T3?]=>T:new…args:[T1?,T2?,T3?]=>T{ //奇迹发生了 //这是一个非常简单的例子。 //bindClass中的实际逻辑要复杂得多,以便保留检查实例等 返回Class.bind{},context; } 类型PublicApi={ MyClass:new myParam:string=>MyClass, MyOtherClass:new myParam:string,myOtherParam:number=>MyOtherClass, }; 函数getPublicApicontext:Context:PublicApi{ 返回{ MyClass:bindClasscontext,MyClass, MyOtherClass:bindClasscontext,MyOtherClass, } } 请注意,即使在VS Intellisense中,严格的类型检查也能很好地工作:

有关更多信息,请参阅:


我不确定是否有真正的动态解决方案,但可以使用重载和泛型来允许使用类型匹配的附加参数

缺点是,您必须为每个附加参数包含一个重载,这意味着您不能允许无限数量的参数

然而,提供足够的重载以满足需求并不困难 对您自己的代码库的需求:

函数bindClasscontext:Context,类:newcontext:Context=>T:new=>T; 函数bindClasscontext:Context,类:新上下文:Context,…args:[T1]=>T:new…args:[T1]=>T; 函数bindClasscontext:Context,Class:newcontext:Context,…args:[T1,T2]=>T:new…args:[T1,T2]=>T; 函数bindClasscontext:Context,Class:newcontext:Context,…args:[T1,T2,T3]=>T:new…args:[T1,T2,T3]=>T; 函数bindClasscontext:Context,类:新上下文:Context,…args:[T1?,T2?,T3?]=>T:new…args:[T1?,T2?,T3?]=>T{ //奇迹发生了 //这是一个非常简单的例子。 //bindClass中的实际逻辑要复杂得多,以便保留检查实例等 返回Class.bind{},context; } 类型PublicApi={ MyClass:new myParam:string=>MyClass, MyOtherClass:new myParam:string,myOtherParam:number=>MyOtherClass, }; 函数getPublicApicontext:Context:PublicApi{ 返回{ MyClass:bindClasscontext,MyClass, MyOtherClass:bindClasscontext,MyOtherClass, } } 请注意,即使在VS Intellisense中,严格的类型检查也能很好地工作:

有关更多信息,请参阅:

您可以使用来表示类的第一个上下文构造函数参数之后的参数元组,如下所示:

function bindClass<C extends Context, A extends any[], T extends ContextDependent>(
  context: C,
  Class: new (context: C, ...rest: A) => T
): new (...args: A) => T {
  return Class.bind({}, context);
}
您可以使用来表示类的第一个上下文构造函数参数之后的参数元组,如下所示:

function bindClass<C extends Context, A extends any[], T extends ContextDependent>(
  context: C,
  Class: new (context: C, ...rest: A) => T
): new (...args: A) => T {
  return Class.bind({}, context);
}