David Thielen
David Thielen

Reputation: 33046

Can I use a generic to call its constructor?

I have a Dictionary class and I would like to do the following:

export class Dictionary<K, V> {
   private table:{ [key: string]: IDictionaryPair<K, V> };
   private nElements:number;

   constructor(src:Dictionary<K, V>) {

            for (var item in src.table)
                if (src.hasOwnProperty(item)) {
                    windward.trap();
                    var valCopy = new V(src[<string>item]);
                    this.setValue(<K>item, valCopy);
                }
   }
}

This would all work great except "var valCopy = new V(src[item]);" is not allowed. Is there a way to do this? Because if the type V has a copy constructor, then this is all valid including type checking.

Is there a way to do this?

thanks - dave

Upvotes: 0

Views: 130

Answers (1)

Fenton
Fenton

Reputation: 251262

All of the type information is erased at runtime, so you need something that will still exist at runtime in order to new up an instance:

export class Dictionary<K, V> {
   private table:{ [key: string]: IDictionaryPair<K, V> };
   private nElements:number;

   constructor(src:Dictionary<K, V>, myType: any) {

            for (var item in src.table)
                if (src.hasOwnProperty(item)) {
                    windward.trap();
                    var valCopy = <V> new myType(src[<string>item]);
                    this.setValue(<K>item, valCopy);
                }
   }
}

You can even constrain it so you can guarantee the constructor signature is what you expect:

export interface MyNewable<T> {
    new(input: string) : T;
}

export class Dictionary<K, V> {
   private table:{ [key: string]: IDictionaryPair<K, V> };
   private nElements:number;

   constructor(src:Dictionary<K, V>, type: MyNewable<V>) {

            for (var item in src.table)
                if (src.hasOwnProperty(item)) {
                    windward.trap();
                    var valCopy = <V> new type(src[<string>item]);
                    this.setValue(<K>item, valCopy);
                }
   }
}

Example using the constrained version (simplified by not passing in a src)

export class MyClass {
    constructor(input: string) {

    }
}

export class Example {
    constructor(input: number) {

    }
}

var d = new Dictionary<string, MyClass>(null, MyClass);

// Complier warning - type `Example` isn't compatible.
var e = new Dictionary<string, MyClass>(null, Example);

Upvotes: 1

Related Questions