10

I need to set a default value of a variable based on its type in Typescript generic classes like below

  class MyClass<T>{
      myvariable: T // Here I want to set the value of this variable 
                    // with the default value of the type passed in 'T'
    }

For example if the T is number then the default value of the variable myvariable should be "0", similarly for string it should be empty string and so on..

2
  • You can't define it in the abstract class; the information of T is not available at runtime. Commented Jul 4, 2016 at 6:41
  • why..? if I have created an instance of this class like var obj = MyClass<string>()...at run time T will be string. Commented Jul 4, 2016 at 6:45

4 Answers 4

12

You can't do that as the actual type which is T will only be known at runtime.

What you can do:

abstract class MyClass<T> {
    myvariable: T;

    constructor() {
        this.myvariable = this.getInitialValue();
    }

    protected abstract getInitialValue(): T;
}

Now you just extend this class, like so:

class MyStringClass extends MyClass<string> {
    protected getInitialValue(): string {
        return "init-value";
    }
}

Edit

What you're asking for can not be done because T only exists in the typescript realm, and it doesn't "survive" the compilation process.

For example, this:

class MyClass<T> {
    myvariable: T;

    constructor(value: T) {
        this.myvariable = value;
    }
}

Compiles into:

var MyClass = (function () {
    function MyClass(value) {
        this.myvariable = value;
    }
    return MyClass;
}());

As you can see, in the compiled version there's no T, so you can't use that information at runtime in order to generate a default value.


Another solution is to have a map of default values:

var defaultValues = {
    "string": "",
    "number": 0,
    "boolean": false
}

class MyClass<T> {
    myvariable: T;

    constructor(value: T) {
        this.myvariable = value;
    }
}

let a = new MyClass<string>(defaultValues.string);
let b = new MyClass<boolean>(defaultValues.boolean);

You can also use static factory methods:

class MyClass<T> {
    myvariable: T;

    constructor(value: T) {
        this.myvariable = value;
    }

    static stringInstance(): MyClass<string> {
        return new MyClass<string>("");
    }

    static numberInstance(): MyClass<number> {
        return new MyClass<number>(0);
    }

    static booleanInstance(): MyClass<boolean> {
        return new MyClass<boolean>(false);
    }
}

let a = MyClass.stringInstance();
let b = MyClass.booleanInstance();
Sign up to request clarification or add additional context in comments.

4 Comments

exactly...that is what I'm asking is there any construct to which I pass T and it gives me the default value of T at run time.
No, there's no T in runtime so you can not use it.. I edited my answer with an example
Don't want to pass anything in the constructor..need something like this myvariable: T =defaultOF(T)...I know T is not there in the javascript after the code generation..
Well, we don't always get what we want... You'll need to workaround the problem that javascript doesn't have the notion of types. If you don't want to pass a value to the ctor then use the first solution I gave in my answer and implement a class per type, or check the 3rd edit of my answer (static factory functions).
0

T is lost at runtime, so you need to pass in the type like a value. And you can do that by passing the constructor.

When I have a similar need, I usually use an interface like this:

interface Type<T> {
     new() : T;
}

And create MyClass like so:

class MyClass<T>{
    myvariable: T;

    constructor(type: Type<T>) {

        this.myvariable = new type();
    }
}

Then I can use MyClass like so:

let myinstance = new MyClass(TheOtherType);

It works for classes, but not for built-ins like string and number.

TheOtherType is the constructor of a class such as:

class TheOtherType {
}

2 Comments

I don't want to pass anything through my constructor and then assign that value to the variable..what I need is there any construct which I can directly assign to my variable like this myvariable: T =defaultOF(T)..
No, not possible. Bugs me too, used that in C# a lot. This is the way I've come up with that works for me.
0

Well I guess I came up with a possible solution. Anyway I must say that Nitzan Tomer is right and the class type is not available in runtime. This is the funny side of TS :)

Here you can check the type of the objects you get in and then set a default value. You could also change the place and the objects to check in order to do it the way you want but I guess it could be a good starting point for you. Notice that you have to do a double cast because TS cannot guarantee that types are compatible. I haven't tried it yet but it compiles well

class MyClass<T>{
      myvariable: T 

    constructor(param: any) {
        if (typeof param === 'string') {
            this.myvariable = <T><any> "";
        }
        else if (typeof param === 'number') {
            this.myvariable = <T><any> 0;
        }
    }  
}

Comments

0

TypeScript types are erased at runtime, so you can't directly set a default value based on the type "T" in a generic class unless you pass in a hint or factory function. To solve this, you can pass a factory or default value to the constructor. You have two options to do this as outlined below:

Option 1 (pass value explicitly):

class MyClass<T> {
  myvariable: T;

  constructor(defaultValue: T) {
    this.myvariable = defaultValue;
  }
}

const numInstance = new MyClass<number>(0);
const strInstance = new MyClass<string>("");
const boolInstance = new MyClass<boolean>(false);

Option 2 (pass a factory function):

class MyClass<T> {
  myvariable: T;

  constructor(factory: () => T) {
    this.myvariable = factory();
  }
}

const numInstance = new MyClass<number>(() => 0);
const strInstance = new MyClass<string>(() => "");
const boolInstance = new MyClass<boolean>(() => false);

TypeScript can't do this automatically because TypeScript’s generics are not available at runtime. Therefore, your current code doesn’t work unless you explicitly tell TypeScript what value to use.

Comments

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.