Generics 带有类参数的泛型类型推断
我遇到了一个问题,根据我传入的类型定义泛型类型 我有一段代码“激活”了一个类,我无法从type参数中获得类型信息,所以我要传入class对象(不是实例)。然而,这打破了类型推断 下面是一个我正在尝试做的简化示例:Generics 带有类参数的泛型类型推断,generics,typescript,Generics,Typescript,我遇到了一个问题,根据我传入的类型定义泛型类型 我有一段代码“激活”了一个类,我无法从type参数中获得类型信息,所以我要传入class对象(不是实例)。然而,这打破了类型推断 下面是一个我正在尝试做的简化示例: interface IActivatable { id: number; name:string; } class ClassA implements IActivatable { public id: number; public name: str
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);
感谢您提供的任何帮助。您的问题是ClassA实际上不是T extends IActivatable类型。事实上,编译后的javascript中的ClassA实际上是一个返回构造函数的函数 TypeScript中的类型信息在编译过程中都会被删除,因此您不能直接使用任何泛型类型,例如在运行时 所以这里是你能做的 通过将名称作为字符串传递,可以按名称创建类。对这包括挥动你的魔杖。您还需要了解工具链中可能影响名称的任何内容,例如任何会压碎名称(导致您的魔术字符串不同步)的缩微器:
类InstanceLoader{
构造函数(私有上下文:对象){
}
getInstance(名称:string,…args:any[]):T{
var instance=Object.create(this.context[name].prototype);
instance.constructor.apply(实例,参数);
返回实例;
}
}
var loader=新的InstanceLoader(窗口);
var-example=loader.getInstance('ClassA');
您还可以在运行时从实例中获取类型名称,我在下面的示例格式中展示了这些名称,这些示例格式取自:
类描述符{
静态getName(inputClass){
var funcNameRegex=/function(.{1,})\(/;
var results=(funcNameRegex.exec((inputClass.constructor.toString());
返回(results&&results.length>1)?结果[1]:“”;
}
}
课例{
}
另一个类扩展了示例{
}
var x=新示例();
var y=新的另一个类();
警报(descripber.getName(x));//示例
警报(Describer.getName(y));//另一个类
这只有在您想要生成“另一个同类”时才相关,因为您可以获取类型名称,然后使用对象创建内容来获取另一个。根据语言规范,您需要通过其构造函数引用类类型。因此,不要使用
类型:T
,而是使用类型:{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);
函数激活器(类型:{new():T;}):T{
//执行以下操作以返回T的新实例。
返回新类型();
}
var classA:classA=激活剂(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);
接口IConstructor{
新(…args:any[]):T;
//或强制执行默认构造函数
//新的():T;
}
界面可激活{
id:编号;
名称:字符串;
}
类ClassA实现IActivatable{
公众id:号码;
公共名称:字符串;
公共广播:字符串;
}
类ClassB实现IActivatable{
公众id:号码;
公共名称:字符串;
公众年龄:人数;
}
函数激活器(类型:IConstructor):T{
返回新类型();
}
常数classA=激活剂(classA);
我想问的是,有没有一种方法可以设置泛型类型并传入函数,而不必多次指定
ClassA
。这也是我得出的基本结论(不同的是我传入的是构造函数,而您传入的是名称)。遗憾的是,没有更好的构造,但我想这就是生活。感谢您的确认。现在可以更轻松地完成。使用blorkfish或我下面的答案。这太蹩脚了:(我的意思是typescript如何处理这个问题。您的答案很好。有点晚(但很有用)的注释-如果您的构造函数使用args,那么new()
也需要-或者更通用的:类型:{new(…args:any[]):T;}
如果有人使用具有多个参数的构造函数实现IActivatable接口,您如何推断参数?因为使用…args:any[]
不是类型安全的。
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
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);
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);