export class Base {
static getSomething():typeof this //<-- change this?
{
var type = typeof this;
return new this['type']();
}
}
export class Foo extends Base {
publicVar:string = 'getThis!';
}
var foo:Foo = Foo.getSomething();
var success:string = foo.publicVar;
the above returns an error because the compiler says Foo.getSomething will return a Base, not a Foo. I wonder if there is another way that lets me call a static function of Foo that the compiler knows will return a Foo.
Ofcourse I can implement it explicitly in Foo, and thus in every class that extends Base, or I could simply typecast it:
var foo:Foo = <Foo> Foo.getSomething();
But I was wondering if there is a way without having to do either of those things, since I'll be using this method a lot
If you follow the Liskov substitution principle, you don't need the type assertion.
Code Example 1 - Substitutable Objects...
module Test {
export class Base {
publicVar: string = 'base';
static getSomething() : Base {
//... read on...
}
}
export class Foo extends Base {
publicVar:string = 'getThis!';
}
}
// No <Foo> type assertion needed
var foo: Test.Foo = Test.Foo.getSomething();
alert(foo.publicVar);
Alternatively, you could create an interface
that tells you the object returned will have a publicVar property and return that...
Code Example 2 - Interface
module Test {
export interface IPublicVarable {
publicVar: string;
}
export class Base {
static getSomething() : IPublicVarable {
//... read on...
}
}
export class Foo extends Base {
publicVar:string = 'getThis!';
}
}
// No <Foo> type assertion needed
var foo: Test.IPublicVarable = Test.Foo.getSomething();
alert(foo.publicVar);
This doesn't solve one other issue you have though - var type = typeof this;
isn't going to give you what you expect at runtime. It is going to give you Function
not Foo
.
To get a type name, you really need to work with an instance (if you use Test.Foo
the type name is Function
once again - which does you no good), so here is an imperfect example using two different subclasses that both satisfy the interface, based on my Obtaining a Class Name at Runtime example:
module Test {
export class Describer {
static getName(inputClass) {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((<any> inputClass).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
}
static getInstanceOf(inputClass) : Test.IPublicVarable {
var name = Describer.getName(inputClass);
return new Test[name]();
}
}
export interface IPublicVarable {
publicVar: string;
}
export class Base {
}
export class Foo extends Base {
publicVar:string = 'foo class';
}
export class Bar extends Base {
publicVar:string = 'bar class';
}
}
var a: Test.Base = new Test.Foo();
var x: Test.IPublicVarable = Test.Describer.getInstanceOf(a);
alert(x.publicVar);
var b: Test.Base = new Test.Bar();
var y: Test.IPublicVarable = Test.Describer.getInstanceOf(b);
alert(y.publicVar);