Typescript 是否存在从派生类推断基类类型的方法?
我正在为我的Typescript 是否存在从派生类推断基类类型的方法?,typescript,generics,Typescript,Generics,我正在为我的TypeScript库开发一项功能,并且一直在解决这个打字问题。请看以下示例: 类基类{…} 类用户扩展基{…} 类产品扩展了基{…} 类CompletelyUnrelated{…} 函数someFunction(源代码:TModel,base:{what_to_type_here}){…}; //期望结果 someFunction(用户、基);//作品 某些功能(产品、基础);//作品 someFunction(完全不相关,基本);//错误 某些功能(用户、产品);//错误 某些功
TypeScript
库开发一项功能,并且一直在解决这个打字问题。请看以下示例:
类基类{…}
类用户扩展基{…}
类产品扩展了基{…}
类CompletelyUnrelated{…}
函数someFunction(源代码:TModel,base:{what_to_type_here}){…};
//期望结果
someFunction(用户、基);//作品
某些功能(产品、基础);//作品
someFunction(完全不相关,基本);//错误
某些功能(用户、产品);//错误
某些功能(产品、用户);//错误
someFunction(用户,完全不相关);//错误
为了进一步解释所需的输出,我希望使用someFunction()
期望User
和Base
作为其参数,因为User扩展了Base
。与产品
和基础
相同。有没有(甚至)方法来实现这一点?有什么接近我想要实现的吗
我试过:
interface-Constructible{//一个用于注释新的可构造类型的接口(任意,放在这里作为上下文)
新(…args:any[]):TModel;
}
类型BaseConstructible=TModel扩展推断TBase?可建造的:任何;
但是,这不起作用,我总是得到可构造的
,结果是:
type Test=BaseConstructible;//返回可构造的
任何帮助/指导都将不胜感激。谢谢
UPDATE:正如@jcalz所指出的,TypeScript
有一个结构化的类型系统,我也知道这一点@jcalz的回答是完全真实和正确的。然而,这并不是我想要的(也许在TypeScript中根本不可能)。以下是一个案例:
函数另一个函数(来源:可构造){
返回(基本:可构造)=>{
//功能体
}
}
其他功能(用户)(产品);//无误
TypeScript
根本不知道或无法从t模型扩展TBase
推断TBase
。我想知道是否有办法让TypeScript
推断TBase
第一件事:TypeScript的类型系统是;粗略地说,这意味着如果两个类型具有相同的形状,那么它们是相同的类型,即使这些类型具有不同的声明。这与爪哇、C++、或C中的标称类型形成了鲜明的对比,其中“代码>类A{{} /Class>和<代码>类B{} <代码>是不同类型,仅仅因为它们有不同的声明。
例如,如果TypeScript中的示例类为,则它们将被视为与空接口{}
相同,并且彼此相同。因此,您可能会看到一些奇怪的行为,比如说,CompletelyUnrelated
,尽管名称不同,实际上被认为与其他类(如Base
)的类型相同。如果您希望编译器将两个类视为不同的,那么仅具有不同的类声明是不够的;您需要这两个类具有不同的成员(或者它们需要具有private
或protected
成员,这将提供更多的功能)
以下是一些具有足够属性的类,Base
、User
、Product
和CompletelyUnrelated
以您想要的方式进行关联:
class Base {
base = "base"
}
class User extends Base {
user = "user"
}
class Product extends Base {
product = "product"
}
class CompletelyUnrelated {
completelyUnrelated = "whatevz";
}
现在我们可以为
someFunction()
编写类型签名。我将其分为两种类型:T
,表示base
构造函数的实例类型;和U
,表示源
构造函数的实例类型。我们希望U
,以便它扩展T
,并且我们希望源
和基
参数成为构造函数:
function someFunction<T, U extends T>(
source: new (...args: any) => U,
base: new (...args: any) => T
) { return null! };
看起来不错someFunction()
在您希望的地方成功或失败。好吧,希望这会有帮助;祝你好运
更新: 如果您想将
someFunction()
分解为一个名为anotherFunction()
的版本,则需要执行更多的类型转换来实现这一点。主要问题是编译器希望另一个函数(sometor)
的返回值是一个确定的类型,因此需要将该类型表示为只允许与sometor
对应的类实例类型的超类型
从概念上讲,您希望类型看起来像(source:new(…args:any)=>U)=>(base:new(…args:any)=>T)=>void
,其中T super U
是表示下限的假设语法,而不是由T extensed U
表示的上限。所以T super U
和U extends T
应该是同一个意思
不幸的是,TypeScript中没有T super U
下限约束。获取相关的功能请求。您可以使用条件类型对这种行为进行排序。您可以编写T extends([U]extends[T]?unknown:never)>:而不是T super U
:这将执行U extends T
检查([U]extends[T]
关闭U
中的联合,如果成功,则变成T extends unknown
,这始终是真的,如果失败,它将变成T extends never
,这本质上总是错误的。那么像这样,
function anotherFunction<U>(source: new (...args: any) => U) {
return <T extends ([U] extends [T] ? unknown : never)>(base: new (...args: any) => T) => {
}
}
这正是您想要的,只是可能错误很奇怪:“Base
不可分配给never
”,虽然为true,但在某种程度上没有帮助“CompletelyUnrelated
不可分配给Base
”。所以这里还有一点限制
好吧,希望这能再次帮助你。祝你好运
第一件事:TypeScript的类型系统是;粗略地说,这意味着如果两种类型具有相同的形状,那么它们是相同的
function anotherFunction<U>(source: new (...args: any) => U) {
return <T extends ([U] extends [T] ? unknown : never)>(base: new (...args: any) => T) => {
}
}
anotherFunction(User)(Base); // okay
anotherFunction(Product)(Base); // okay
anotherFunction(Base)(Product); // error!
// -----------------> ~~~~~~~
// Type 'Product' is not assignable to type 'never'
anotherFunction(CompletelyUnrelated)(Base); // error!
// --------------------------------> ~~~~
// Type 'Base' is not assignable to type 'never'
anotherFunction(User)(Product); // error!
anotherFunction(Product)(User); // error!
anotherFunction(User)(CompletelyUnrelated); // error!