Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using generics inside method

Tags:

typescript

Why I get an error "Type 'AbstractPopup' is not assignable to type T" on the return of popupFactory(...) method ? Please ignore other errors this is just a test code to understand better how generic works.

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, {});
like image 898
Hivaga Avatar asked Jan 19 '26 14:01

Hivaga


1 Answers

A generic function implies it should work based on the generic type parameter passed to it. In your case the method decides the return type based on the enum parameter, not based on the generic parameter. So the method is not really generic.

The reason the compiler complains is that, since you could pass any T derived from AbstractPopup it can't really check that the type you return will be compatible with the specific T you pass to the function. Consider the following valid code:

class OtherConcretePopup extends AbstractPopup{}
var p = popupFactory<OtherConcretePopup>(PopupType.ConcretePopup, {})

The code would be valid, but you return a ConcretePopup even though the return type is OtherConcretePopup

The simplest solution would be to have several overloads to the method for each popup type:

function popupFactory(popupType: PopupType.OtherConcretePopup, data: {}): OtherConcretePopup
function popupFactory(popupType: PopupType.ConcretePopup, data: {}): ConcretePopup
function popupFactory(popupType: PopupType, data: {}): AbstractPopup 
{
    var popup: AbstractPopup = null;
    switch (popupType)
    {
        case PopupType.ConcretePopup:
        {
                popup = new ConcretePopup();
                break;
        }
    }

    return popup;
}

Or you could pass the constructor as a parameter and eliminate the need for the switch altogether, but this a good option only if all the constructors have the same number of parameters and the initialization is the same for all:

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

var p = popupFactory(ConcretePopup, {})
like image 120
Titian Cernicova-Dragomir Avatar answered Jan 22 '26 16:01

Titian Cernicova-Dragomir



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!