9

Lets say I have a base class with some property dataItems which is array of DataItem:

export class BaseClass{
   dataItems:DataItems[];
}

Then I have several classes which extend BaseClass and their dataItems property is an array of some class which extends DataItems:

export class BetterClass extends BaseClass{
   dataItems:BetterDataItems[];
}

export class BestClass extends BaseClass{
   dataItems:BestDataItems[];
}

Now I want to add a method in BaseClass which creates dataItems and adds them to array. Would it be possible to do all of this in BaseClass? I need to create instance of BetterDataItems or BestDataItems, depending on the class used.

At the moment I simply added:

dataItemType: typeof DataItem; 

property to BaseClass and in each class extending BaseClass I override this variable with the proper data item type:

in BetterClass:

dataItemType: typeof BetterDataItem = BetterDataItem;

in BestClass:

dataItemType: typeof BestDataItem = BestDataItem;

And then, in BaseClass I do this:

var dataItem = new this.dataItemType();

This works fine but my question is - would it be possible to avoid having dataItemType property at all? Can I find a type of dataItems array and create a new instance then?

Thanks!

2 Answers 2

4
+50

TypeScript 1.6 code:

class DataItems {

}

class BaseClass {
   dataItems:DataItems[];
   dataItemType: typeof DataItems = DataItems;
}

compiles to:

var DataItems = (function () {
    function DataItems() {
    }
    return DataItems;
})();
var BaseClass = (function () {
    function BaseClass() {
        this.dataItemType = DataItems;
    }
    return BaseClass;
})();

And you can see that type information for dataItems property is lost in BaseClass. That's how TypeScript compiler works. It does not support runtime checking. So answer to your question is no.


Your workaround with dataItemType: typeof BetterDataItem = BetterDataItem; works because you make the TypeScript compiler to add JS command: this.dataItemType = BetterDataItem; which can be used later.

Sign up to request clarification or add additional context in comments.

Comments

4

Option 1: You could override the method in each sub class...

export class BaseClass{
   dataItems:DataItem[];

   create() {
       this.dataItems.push(new DataItem());
   }
}

export class BetterClass extends BaseClass{
   dataItems:BetterDataItem[];

   create() {
       this.dataItems.push(new BetterDataItem());
   }
}

export class BestClass extends BaseClass{
   dataItems:BestDataItem[];

      create() {
       this.dataItems.push(new BestDataItem());
   }
}

Option 2: But if you introduce a generic base class, you can remove the need to define the dataItems property on each class and also create different instances.

type MyT = typeof DataItem;

export class GenericBaseClass<T extends DataItem> {
    dataItems:T[];

    constructor(private dataType: MyT) {

    }

    create() {
        this.dataItems.push(<T>new this.dataType())
    }

}

export class BaseClass extends GenericBaseClass<DataItem> {
   constructor() {
       super(DataItem);
   }
}

export class BetterClass extends GenericBaseClass<DataItem> {
   constructor() {
       super(BetterDataItem);
   }
}

export class BestClass extends GenericBaseClass<DataItem> {
   constructor() {
       super(BestDataItem);
   }
}

2 Comments

+1; For the sake of completeness, I think you can use instanceof operator in BaseClass but it is really an anti-pattern in this case. (typescriptlang.org/Content/… 4.13 Type Assertions)
Thanks. So I assume it is not possible to simply get a type of a class from a variable and then create a class? instanceof would require checking each type, so it is really not a good solution.

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.