Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 在方法内部使用泛型_Typescript - Fatal编程技术网

Typescript 在方法内部使用泛型

Typescript 在方法内部使用泛型,typescript,Typescript,为什么在返回popupFactory(…)方法时出现错误“类型'AbstractPopup'不可分配给类型T”?请忽略其他错误这只是一个测试代码,以更好地理解泛型如何工作 function popupFactory<T extends AbstractPopup>(popupType: PopupType, data: {}): T { var popup: AbstractPopup; switch (popupType) { case

为什么在返回popupFactory(…)方法时出现错误“类型'AbstractPopup'不可分配给类型T”?请忽略其他错误这只是一个测试代码,以更好地理解泛型如何工作

function popupFactory<T extends AbstractPopup>(popupType: PopupType, data: {}): T 
{
    var popup: AbstractPopup;

    switch (popupType)
    {

        case PopupType.ConcretePopup:
        {
                popup = new ConcretePopup();
                break;
        }
    }

    return popup;
}

abstract class AbstractPopup
{
    type: PopupType;
}

class ConcretePopup extends AbstractPopup{}

var p = popupFactory<ConcretePopup>(PopupType.ConcretePopup, {});
函数popupFactory(popupType:popupType,数据:{}):T
{
var弹出:抽象弹出;
开关(popupType)
{
案例PopupType.ConcretePopup:
{
popup=新的popup();
打破
}
}
返回弹出窗口;
}
抽象类抽象弹出窗口
{
类型:PopupType;
}
类ConcretePopup扩展了AbstractPopup{}
var p=popupFactory(poputype.ConcretePopup,{});

泛型函数意味着它应该基于传递给它的泛型类型参数工作。在您的例子中,该方法基于enum参数而不是泛型参数来决定返回类型。因此,该方法并非真正通用

编译器抱怨的原因是,由于您可以传递从
AbstractPopup
派生的任何
T
,因此它无法真正检查您返回的类型是否与传递给函数的特定
T
兼容。考虑下面的有效代码:

class OtherConcretePopup extends AbstractPopup{}
var p = popupFactory<OtherConcretePopup>(PopupType.ConcretePopup, {})
或者,您可以将构造函数作为参数传递,完全不需要切换,但只有在所有构造函数都具有相同数量的参数且所有构造函数的初始化都相同的情况下,这才是一个好选项:

function popupFactory<T extends AbstractPopup>(popupType: new() => T, data: {}): T
{
    var popup = new popupType();
    return popup;
}

var p = popupFactory(ConcretePopup, {})
函数popupFactory(poputype:new()=>T,数据:{}):T
{
var popup=new popupType();
返回弹出窗口;
}
var p=popupFactory(ConcretePopup,{})

您可以使用下面的泛型工厂方法来创建任何派生类的实例,而不是使用开关。注意这里的
new()=>T
签名,它表示一个没有参数构造函数的类型,因此,如果派生类名有如下默认的无参数构造函数,您可以在这里直接传递派生类名-

function popupFactory<T extends AbstractPopup>(popupType:  new () => T, data: {}): T 
{
    var newPopup: T;
    newPopup = new popupType();
    return newPopup;
}

abstract class AbstractPopup
{
    //type: PopupType;
}


class ConcretePopup extends AbstractPopup{  
}

var p = popupFactory(ConcretePopup, {}); // creates instance of ConcretePopup class 
函数popupFactory(poputype:new()=>T,数据:{}):T
{
var:T;
newPopup=新的popupType();
返回新弹出窗口;
}
抽象类抽象弹出窗口
{
//类型:PopupType;
}
类ConcretePopup扩展了AbstractPopup{
}
var p=popupFactory(ConcretePopup,{});//创建ConcretePopup类的实例
但是,如果派生类在构造函数中有1个或多个参数,并且在创建该类的实例时需要设置参数值,则可以遵循以下方法-

function popupFactory<T extends AbstractPopup>(popupType:  new (obj:Object) => T, data: {}): T 
{
    var newCust: T;
    newCust = new popupType(data);
    return newCust;
}

abstract class AbstractPopup
{
    //type: PopupType;
}


class ConcretePopup extends AbstractPopup{
    public fname: string;
    public lname: string;
    constructor(obj:Object) {
        super();
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                if (key == "fname") {
                    this.fname = obj["fname"];
                }
                if (key == "lname") {
                    this.lname = obj["lname"];
                }
            }
        }       

    }
}
var p = popupFactory(ConcretePopup, {"fname":"Niladri","lname":"D"});
console.log(p.fname); // Niladri
console.log(p.lname); // D
函数popupFactory(poputype:new(obj:Object)=>T,数据:{}):T
{
var-newCust:T;
newCust=新的popupType(数据);
返回newCust;
}
抽象类抽象弹出窗口
{
//类型:PopupType;
}
类ConcretePopup扩展了AbstractPopup{
公共fname:string;
公共名称:字符串;
构造函数(obj:Object){
超级();
用于(输入obj){
if(对象hasOwnProperty(键)){
如果(键==“fname”){
this.fname=obj[“fname”];
}
如果(键==“lname”){
this.lname=obj[“lname”];
}
}
}       
}
}
var p=popupFactory(具体弹出,{“fname”:“Niladri”,“lname”:“D”});
console.log(p.fname);//尼拉德利
console.log(p.lname);//D
这里我将
poputype:new(obj:Object)=>T
作为一个类型传递,该类型将
Object
作为其构造函数中的参数。因此,我们可以将所需的属性和值作为对象传递,这是通过
data
参数完成的。但是这种方法的缺点是您必须手动提取派生类的属性,正如您在上面的
ConcretePopup
类构造函数中看到的那样

这里是一个链接到一个工作小提琴


如果要使用通用工厂,为什么要使用开关盒?您的函数返回类型是T。T可以是任何扩展AbstractPopup的类。但是您实际上返回了popup,它是AbstractPopup类型的。AbstractPopup与T的类型不同。如果我使用popupFactory(…)调用您的函数,您的方法应该返回MyCustomPopup的实例。没有。键入时没有看到你的帖子,我想我来晚了。@Niladri是的,但是你的帖子有更多关于构造函数传递方法的详细信息,让OP决定他想要哪一个:-)好的,,我在上一个方法的顶部为构造函数添加了额外的参数。您的回复实际上让我找到了这个解决方案,它看起来不那么冗长,并且保留了类型安全性。函数popupFactory(popupType:popupType,数据:{}):T{var popup:AbstractPopup;开关(popupType){case popupType.ConcretePopup:{popup=new ConcretePopup();break;}}返回任意弹出;}对任何类型使用类型断言总是有效的,但实际上是一种类型安全的方法。正如我的第一个示例所示,您可能会错误匹配类型和枚举,编译器将不知道这一点。我强烈推荐另一种解决方案
function popupFactory<T extends AbstractPopup>(popupType:  new (obj:Object) => T, data: {}): T 
{
    var newCust: T;
    newCust = new popupType(data);
    return newCust;
}

abstract class AbstractPopup
{
    //type: PopupType;
}


class ConcretePopup extends AbstractPopup{
    public fname: string;
    public lname: string;
    constructor(obj:Object) {
        super();
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                if (key == "fname") {
                    this.fname = obj["fname"];
                }
                if (key == "lname") {
                    this.lname = obj["lname"];
                }
            }
        }       

    }
}
var p = popupFactory(ConcretePopup, {"fname":"Niladri","lname":"D"});
console.log(p.fname); // Niladri
console.log(p.lname); // D