Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript generics extending class and interface

Tags:

typescript

I have a Typescript class which includes a generic which needs to extend another class and implement an interface. Here is an example

interface IHasImage {
  imageUrl():string; 
}
class Model {
}
class View<T extends Model & IHasImage> {
}

This is the sort of syntax I have seen elsewhere but is there a way of doing this in Typescript?

edit: Try pasting the following in to the playground:http://www.typescriptlang.org/Playground

...[removed edit 1 code]

edit 2: Answer and reasoning

(I apologise, the first example had a few flaws!) I have marked the correct answer below, although it probably needs a few pointers as outlined in this github issue (https://github.com/Microsoft/TypeScript/issues/1885)

Given the following code you can see the methodology works.

playground screenshot

The only other thing to say is that trying to implement the interface from a class that does not extend the base class also fails. However because Typescript checking is based on the structure of the object, it will succeed if you manually add the name property to the class.

enter image description here

This is also why it succeeds with the ModelCorrect which extends but doesn't implements.

like image 942
Dave Taylor Avatar asked Feb 02 '15 08:02

Dave Taylor


People also ask

Can a class extend an interface TypeScript?

In TypeScript, interfaces can also extend classes, but only in a way that involves inheritance. When an interface extends a class, the interface includes all class members (public and private), but without the class' implementations.

Can we extend generic class?

You can subtype a generic class or interface by extending or implementing it. The relationship between the type parameters of one class or interface and the type parameters of another are determined by the extends and implements clauses.

Does TypeScript support generic interface?

TypeScript - Generic Interface The above IProcessor is a generic interface because we used type variable <T> . The IProcessor interface includes the generic field result and the generic method process() that accepts two generic type parameters and returns a generic type. As you learned, you can use interface as type.

Does TypeScript support generic classes?

TypeScript fully supports generics as a way to introduce type-safety into components that accept arguments and return values whose type will be indeterminate until they are consumed later in your code.


Video Answer


3 Answers

Typescript is not so restrictive as Java or C# so you can do things like that:

interface IHasImage {
    imageUrl():string; 
}

class Model {
}

// use the Model class like an interface
interface IHasImageModel extends IHasImage, Model{
}

class View<T extends IHasImageModel> {
    constructor(arg :T){
       arg.imageUrl();
    }
}

Edit: In TypeScript 1.6 you can use Intersection types:

interface IHasImage {
    imageUrl():string; 
}

class Model {
}

class View<T extends IHasImage & Model> {
    constructor(arg :T){
       arg.imageUrl();
    }
}
like image 194
Markus Avatar answered Oct 07 '22 15:10

Markus


It looks like this is the only way of doing it that I can find. Not perfectly clean but it does the right thing.

interface IHasImage extends Model{  
  imageUrl():string; 
}

class Model {
}

class View<T extends IHasImage> {
}

Here is a screenshot from the playground verifying that it works:

playground

Edit: Added correct workaround.

like image 32
dignifiedquire Avatar answered Oct 07 '22 14:10

dignifiedquire


Missing in the example is what T will be:

In the example below i have added an implementation for T, that can be used as the generic constraint.

interface IHasImage {
  imageUrl():string; 
}

class Model {
}

class ModelWithImage extends Model implements IHasImage {

    imageUrl():string
    {
     return "http://thepetwiki.com/images/thumb/Kitten.jpg/400px-Kitten.jpg";
    }   
}


class View<T extends ModelWithImage>
{
    value:T;

    constructor(arg:T)
    {   
        this.value=arg;
    }       
}
like image 39
Martijn Avatar answered Oct 07 '22 16:10

Martijn