I have a class with multiple generic properties defined like this:
export class MainClass<
A = string,
B = number,
C = boolean> {
propA: A
propB: B
propC: C
}
It works fine if I fully define 3 types:
let mainClass = new MainClass<string, string, string>
But later I want to create a new instance and only define the 3rd type:
let mainClass2 = new MainClass< , ,custom-type>
Can we omit defining any generic (it gets the default type) and only define the ones we need?
Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class.
Generics allow creating 'type variables' which can be used to create classes, functions & type aliases that don't need to explicitly define the types that they use. Generics makes it easier to write reusable code.
This article opts to use the term type variables, coinciding with the official Typescript documentation. T stands for Type, and is commonly used as the first type variable name when defining generics. But in reality T can be replaced with any valid name.
Assigning Generic Parameters By passing in the type with the <number> code, you are explicitly letting TypeScript know that you want the generic type parameter T of the identity function to be of type number . This will enforce the number type as the argument and the return value.
The only way I can think of is to create subclasses that take different type arguments.
I have illustrated your <,,type>
example below. The type annotations are only there to show you what you (effectively) get - you don't need to add the annotations in real life here.
class MainClass<A = string, B = number, C = boolean> {
propA: A
propB: B
propC: C
}
class MainClassB<
C = boolean> extends MainClass<string, number, C> {
}
let example1: MainClass<string, string, string> = new MainClass<string, string, string>();
let example2: MainClass<string, number, number> = new MainClassB<number>();
The basic concept is that the subclass takes whatever combination of type arguments you want, and returns a class with the three properties of MainClass
. You can create various combinations if you want to support the various one or two default situations (eliminating the combinations that can be satisfied by the original type argument order).
I have jammed a function in that accepts MainClass
to show all the resulting types are structurally compatible:
class MainClass<A = string, B = number, C = boolean> {
propA: A
propB: B
propC: C
}
class MainClassC<C> extends MainClass<string, number, C> {
}
class MainClassAC<A, C> extends MainClass<A, number, C> {
}
class MainClassBC<B, C = boolean> extends MainClass<string, B, C> {
}
function processMainClass(input: MainClass) {
console.log(input.propA, input.propB, input.propC);
}
let a = new MainClass<string>();
processMainClass(a);
let b = new MainClassBC<number>();
processMainClass(b);
let c = new MainClassC<boolean>();
processMainClass(c);
let ab = new MainClass<string, number>();
processMainClass(ab);
let ac = new MainClassAC<string, boolean>();
processMainClass(ac);
let bc = new MainClassBC<number, boolean>();
processMainClass(bc);
let abc = new MainClass<string, number, boolean>();
processMainClass(abc);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With