Home > Net >  Typescript generic class with parameterless constructor
Typescript generic class with parameterless constructor

Time:08-01

consider the following class:

class Gen<Type> {
  lst1 :Type[];
  lst2 :Type[];
  constructor() {
    this.lst1 = [];
    this.lst2 = [];
  }
  add1(a:Type){
    console.log(typeof a);
    this.lst1[0]=a;
  }
  add2(a:Type){
    console.log(typeof a);
    this.lst2[0]=a;
  }
}
 
const b = new Gen();
b.add1("string");
console.log(b.lst1);
b.add2(1);
console.log(b.lst2);

Output

[LOG]: "string"  
[LOG]: ["string"]
[LOG]: "number"
[LOG]: [1]

Playground Link

It does not give errors and runs. Note that the constructor is parameterless. Is there any enforcement here on what Type can be? Is Type in this case equivalent to the any type?

Edit: We can explicitly specify the Type as mentioned in @Alex Wayne's comment

const b = new Gen<string>(); // explicitly set `Type`

CodePudding user response:

Unspecified, and unconstrained, generic type parameters assume a type of unknown.

In fact, unconstrained generic parameters are implicitly constrained by unknown.

// Types A and B are 100% equivalent.
type A<T> = T
type B<T extends unknown> = T

If you hover over the b from your code in your IDE (or the Typescript playground) you should see the full type of that value. In this case you would see:

const b = new Gen(); // Gen<unknown>

unknown can accept any value, but in order to use it, you have to do runtime tests to figure out what it is.

For example:

const b = new Gen(); // Gen<unknown>
b.add1("hello, world!");
const fromLst1 = b.lst1[0] // unknown

fromLst1.toUpperCase() // type error
if (typeof fromLst1 === 'string') fromLst1.toUpperCase() // fine

Is there any enforcement here on what Type can be? Is Type in this case equivalent to the any type?

unknown has type safety because you must prove the value is a certain type before Typescript will let you use it as that type. The any type lets you use the value as anything without that testing.

So this is technically type safe because you can't do anything inherently unsafe with unknown.

See Playground


In C# for example, we do not need constructor parameters to define T in something like class Gen{}. Is Typescript forcing the use of synthetic parameters for the sake of more specifically defining Type?

You can always explicitly pass in your own type, which is probably expected if the type can't be inferred from an argument. Otherwise you can't do much with the values it collects.

For example:

const b = new Gen<string>(); // explicitly set `Type`

b.add("hello, world!");
b.add(123); // error

b.lst1[0].toUpperCase() // works

CodePudding user response:

Try this out:

type newtype = string;

class Gen<type extends newtype> {
  lst1 :type[];
  lst2 :type[];
  constructor() {
    this.lst1 = [];
    this.lst2 = [];
  }
  add1(a:type){
    console.log(typeof a);
    this.lst1[0]=a;
  }
  add2(a:type){
    console.log(typeof a);
    this.lst2[0]=a;
  }
}

const b = new Gen();
b.add1('string');
console.log(b.lst1);
b.add2(1);
console.log(b.lst2);

This would help you restrict the type to just string and you can add other types to newtype like this:

type newtype = string | number | etc;

  • Related