[英]Generic Type Inference with Class Argument
我遇到一个问题,该问题是基于传入的类型定义泛型。
我有一段代码“激活”一个类,我无法从类型参数中获取类型信息,因此我传入了类对象(而不是实例)。 但是,这打破了类型推断。
这是我要执行的操作的简化示例:
interface IActivatable {
id: number;
name:string;
}
class ClassA implements IActivatable {
public id: number;
public name: string;
public address:string;
}
class ClassB implements IActivatable {
public id: number;
public name: string;
public age: number;
}
function activator<T extends IActivatable>(type:T): T {
// do stuff to return new instance of T.
}
var classA:ClassA = activator(ClassA);
到目前为止,我唯一能想到的解决方案是将type
参数的type
更改为any
并手动设置通用类型(如下所示)。 但是,这似乎long之以鼻,还有另一种方法可以实现这一目标。
function activator<T extends IActivatable>(type:any): T {
// do stuff to return new instance of T.
}
var classA:ClassA = activator<ClassA>(ClassA);
谢谢你提供的所有帮助。
根据语言规范,您需要通过其构造函数来引用类类型。 因此,不要使用type:T
,而是使用以下type: { new(): T;}
:
function activator<T extends IActivatable>(type: { new(): T ;} ): T {
// do stuff to return new instance of T.
return new type();
}
var classA: ClassA = activator(ClassA);
Typescript团队建议这样做:
基本上与blorkfish的答案相同,但提取到界面。
interface IConstructor<T> {
new (...args: any[]): T;
// Or enforce default constructor
// new (): T;
}
interface IActivatable {
id: number;
name: string;
}
class ClassA implements IActivatable {
public id: number;
public name: string;
public address: string;
}
class ClassB implements IActivatable {
public id: number;
public name: string;
public age: number;
}
function activator<T extends IActivatable>(type: IConstructor<T>): T {
return new type();
}
const classA = activator(ClassA);
TypeScript中的类型信息在编译过程中会全部删除,因此您不能直接使用任何通用类型,例如在运行时。
所以这就是你可以做的...
您可以通过将名称作为字符串传递来按名称创建类。 是; 这涉及挥舞你的魔术弦。 您还需要注意工具链中可能影响名称的所有内容,例如,任何粉碎器都会压碎名称(导致魔术字符串不同步):
class InstanceLoader<T> {
constructor(private context: Object) {
}
getInstance(name: string, ...args: any[]) : T {
var instance = Object.create(this.context[name].prototype);
instance.constructor.apply(instance, args);
return <T> instance;
}
}
var loader = new InstanceLoader<IActivatable>(window);
var example = loader.getInstance('ClassA');
您还可以在运行时从实例中获取类型名称,我以下面的示例格式显示了该格式,该格式取自在运行时获取TypeScript类名称 :
class Describer {
static getName(inputClass) {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((<any> inputClass).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
}
}
class Example {
}
class AnotherClass extends Example {
}
var x = new Example();
var y = new AnotherClass();
alert(Describer.getName(x)); // Example
alert(Describer.getName(y)); // AnotherClass
仅当您要生成“相同类型的另一个”(可以获取类型名称,然后使用对象创建的东西来获取另一个)时,这才有意义。
您的问题是ClassA实际上不是T类型扩展的IActivatable。 实际上,已编译javascript中的ClassA实际上是一个返回构造函数的函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.