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]
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? IsType
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
.
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;