Is it possible to call generic static functions or variables like this: T.staticproc()?
How is T declared?
Example;
class ViewModel {
static defaultTemplate = 'editMask';
firstname:string;
lastname:string;
constructor (firstname:string, lastname:string) {
this.firstname = firstname;
this.lastname = lastname;
}
}
function render<T> (viewModel:T, template?:string) {
// That is what I want: T.defaultTemplate
var template = template || T.defaultTemplate;
// .....
}
// default
render(new ViewModel('Luke', 'Skywalker'));
// or do something special
render(new ViewModel('Luke', 'Skywalker'),'editMaskAdvanced');
The problem is that you only have access to the instance within your function. The constructor though will contain any static properties, so something like this should work:
class ViewModel {
static defaultTemplate = 'editMask';
firstname:string;
lastname:string;
constructor (firstname:string, lastname:string) {
this.firstname = firstname;
this.lastname = lastname;
}
}
function render<T extends ViewModel> (viewModel:T, template?:string) {
// That is what I want: T.defaultTemplate
var template = template || (<typeof ViewModel> viewModel.constructor).defaultTemplate;
// .....
}
// default
render(new ViewModel('Luke', 'Skywalker'));
// or do something special
render(new ViewModel('Luke', 'Skywalker'),'editMaskAdvanced');
The T extends ViewModel isn't required, but it ensures that you are using the right type of ancestor. Currently the constructor isn't properly typed, therefore you have to assert the type. I think there is a ticket for that somewhere.
Nice.
I use for <typeof ViewModel> an abstract class DefaultTemplate so I'm not depending on ViewModel.Perhaps it would be useful to have something like a static interface.
abstract class DefaultTemplate {
static defaultTemplate:string;
}
class ViewModel {
static defaultTemplate = 'editMask';
firstname:string;
lastname:string;
constructor (firstname:string, lastname:string) {
this.firstname = firstname;
this.lastname = lastname;
}
}
function render<T> (viewModel:T, template?:string) {
// That is what I want: T.defaultTemplate
// var template = template || T.defaultTemplate;
var template = template || (<typeof DefaultTemplate> viewModel.constructor).defaultTemplate;
console.log ('template:', template);
// .....
}
// default
render(new ViewModel('Luke', 'Skywalker'));
// or do something special
render(new ViewModel('Luke', 'Skywalker'),'editMaskAdvanced');
Why not make it an instance method instead?
interface DefaultTemplate {
defaultTemplate(): string;
}
class ViewModel implements DefaultTemplate {
defaultTemplate() { return 'editMask'; }
firstname: string;
// ...
}
function render(viewModel: DefaultTemplate, template?: string) {
var template = template || viewModel.defaultTemplate();
// .....
}
If you do need to access it statically (without an instance) you can still do that with ViewModel.prototype.defaultTemplate().
If something is static you should not declare it as an instance member. That is not a good approach.
function render<T extends DefaultTemplate> (viewModel:T, template?:string) {
// That is what I want: T.defaultTemplate
var template = template || (<typeof ViewModel> viewModel.constructor).defaultTemplate;
// .....
}
If you extend T like <T extends DefaultTemplate> the typescript compiler could implement access to static methods or variables like this T.defaultTemplate. That would improve typescript.
looks like the issue is addressed. please reopen if not the case.
Sorry to necro this old issue, I'm working through a use case where I'd like to access the static members of a class, but do not have access to an instantiated object of this class. As such I can't use the solution above.
This hopefully demonstrates the issue:
abstract class A {
static fields: { [fieldName: string]: any };
}
class B extends A {
static fields: { [fieldName: string]: any } = { 'testB': 'testB' };
}
class C extends A {
static fields: { [fieldName: string]: any } = { 'testC': 'testC' };
}
class Wrapper<T extends A>{
foo(): void {
console.log(T.fields.testB); // compiler error: "'T' only refers to a type, but is being used as a value here"
console.log(T.fields.testC); // compiler error: "'T' only refers to a type, but is being used as a value here"
}
}
let bWrapped = new Wrapper<B>();
bWrapped.foo();
let cWrapped = new Wrapper<C>();
cWrapped.foo();
@ZackDeRose Types are erased. You have to give Wrapper a reference to B or C.
@RyanCavanaugh - this seems to work:
abstract class A {
static fields: { [fieldName: string]: any };
}
class B extends A {
static fields: { [fieldName: string]: any } = { 'testB': 'testB' };
}
class C extends A {
static fields: { [fieldName: string]: any } = { 'testC': 'testC' };
}
class Wrapper<T extends A>{
constructor(private classRef: typeof A) { };
foo(): void {
console.log(this.classRef.fields.testB);
console.log(this.classRef.fields.testC);
}
}
let bWrapped = new Wrapper<B>(B);
bWrapped.foo();
let cWrapped = new Wrapper<C>(C);
cWrapped.foo();
Unfortunately, my use case is attempting to make a generic Angular component (analogous to Wrapper in this example). I'll have to look into the dependency injector to see if I can do something like this solution; but that's an Angular issue now. Thanks for your assistance!!
Most helpful comment
If something is static you should not declare it as an instance member. That is not a good approach.
If you extend T like
<T extends DefaultTemplate>the typescript compiler could implement access to static methods or variables like thisT.defaultTemplate. That would improve typescript.