I want to do something that's probably unorthodox (and borderline useless if we're being honest) so here we go:
I want to pass a literal as a Generic parameter and then instantiate it. Consider the following example:
const log = console.log;
class Root<T = {}> {
// public y: T = {}; // this obviously doesn't work
// again this won't work because T is used a value. Even if it worked,
// we want to pass a literal
// public y: T = new T();
public x: T;
constructor(x: T) {
this.x = x;
}
}
class Child extends Root<{
name: "George",
surname: "Typescript",
age: 5
}> {
constructor() {
// Duplicate code. How can I avoid this?
super({
name: "George",
surname: "Typescript",
age: 5
});
}
foo() {
// autocomplete on x works because we gave the type as Generic parameter
log(`${this.x.name} ${this.x.surname} ${this.x.age}`);
}
}
const main = () => {
const m: Child = new Child();
m.foo();
};
main();
This works but I have to pass the literal twice. Once on generic for autocompletion to work and once on constructor for initialization. Ugh.
One other way to do it would be to declare my literal outside of Child
. Like this:
const log = console.log;
class Root<T = {}> {
// public y: T = {}; // this obviously doesn't work
// again this won't work because T is used a value. Even if it worked,
// we want to pass a literal
// public y: T = new T();
public x: T;
constructor(x: T) {
this.x = x;
}
}
// works but ugh..... I don't like it. I don't want to declare things outside of my class
const literal = {
name: "George",
surname: "Typescript",
age: 5
}
class Child extends Root<typeof literal> {
constructor() {
super(literal);
}
foo() {
// autocomplete on x works because we gave the type as Generic parameter
log(`${this.x.name} ${this.x.surname} ${this.x.age}`);
}
}
const main = () => {
const m: Child = new Child();
m.foo();
};
main();
Is there any magical way to instantiate the Generic type without explicitly providing it again through a constructor?
You could use an intermediate wrapper that would take care of both expanding the generic and calling the constructor:
function fromRoot<T>(x: T) {
return class extends Root<T> {
constructor() {
super(x)
}
}
}
and then:
class Child extends fromRoot({
name: "George",
surname: "Typescript",
age: 5
}) { etc }
PG
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