27

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.

1
  • i think there is a bug in the example. this in the constructor is not the generic type value. Class should have a Model:T property or constructur can accept a value:T argument Commented Feb 2, 2015 at 19:52

3 Answers 3

33

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();
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

what does class View<T> actually mean?
@SuperUberDuper This is a question for a new stackoverflow entry. In short it is the typescript way for a generic class typescriptlang.org/docs/handbook/generics.html#generic-classes You can use this class with all types which fulfilled the requirements "extens IHasImage & Model"
15

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.

5 Comments

I tried that, and it does compile but I don't think it does what I'm looking for becuase when I try to do this.model.imageUrl() it complains the T doesn't have an imageUrl function
i'll give that a go, I thought I tried that but might not have done
This almost works, It allows correct use of the model property however for some reason it doesn't restrict to classes that extend the base class... I have created an issue in github explaining this further github.com/Microsoft/TypeScript/issues/1885
There are serious issues with the provided example. If T needs to extend Model and Implement IHasImage the real implementation class is missing. That would be something like class ModelWithImage extends Model Implements IHasImage {} In that case, that class can be use as the Type parameter constraint, or an additional interface can be added.
This answer has the right idea which is why I have marked it but I have added a full explanation (and fixed the code! ...sorry) in an edit above
4

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;
    }       
}

1 Comment

the model extends is too specific here unfortunately as many kinds of model may have the same IHasImage functionality

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.