When inheriting from a class, you have to use the super property to pass the arguments required to the constructor method of the parent class, therefore, you have to remember what are the required fields, so you'll to do the following for example:
class Person {
constructor(name: string, age: number) {
// ...
}
}
class Boy extends Person {
constructor(name: string, age: number) { //see, I have to remember property & type
super(name, age);
}
}
So, I was thinking of a way of doing this, one of the solutions is to change from using positional arguments to named arguments, so you can use the builder pattern to achieve this, then you'll use an interface, and you'll share that interface between the child and the parent, so:
interface PersonProps {
name: string;
age: number;
}
class Person {
constructor(props: PersonProps) {
// props.name ...... props.age
}
}
class Boy extends Person {
constructor(personSuper: PersonProps) {
super(personSuper);
}
}
Now the problem with this approach is that we're breaking the rule of cohesion, which means that all the code that is related together should go in a single standalone unit.
So, to write a better code, -of course- you'll split these files into multiple files, so the Person class should go to a separate file, and the Boy class should go to a separate file,
but the problem is that each of these two files is depending on the PersonProps interface,
In my opinion, it's not a good idea to make a separate file for that interface, because the Person class and that interface are highly related together, so what I'll be doing is to let the PersonProps interface live with the Person class in one file.
So here is the file tree now:
.
├── Boy.js
├── Boy.ts
├── Person.js
├── Person.ts
└── tsconfig.json
Now, The Person class is complete, the problem now is with the Boy class, because it also depends on the PersonProps interface.
So you might be thinking that I will export the PersonProps interface from the Person.ts module, in fact, I'll not, basically because you may have more than one class in one file, for example, the Person.ts file may later include more than one class, and not all of those classes will have an interface, therefore, we'll break the pattern, and slowly the code will become garbage,
therefore, what I'm looking for, is to include that interface inside the Person class, then all of the instances of that Person class will inherit the PersonProps interface within the instance.
That's a lot of talking, here is how both files look like now:
Person.ts:
interface PersonProps {
name: string;
age: number;
}
class Person {
constructor(props: PersonProps) {
// props.name ...... props.age
}
}
Boy.ts:
import { Person } from "./Person";
class Boy extends Person {
constructor(personSuper: PersonProps) {
super(personSuper);
}
}
Now We need to connect the Boy.ts with the PersonProps interface, one of the folks will say "Hey, just go ahead and export the interface from Person.ts, export interface PersonProps..."
That solution might work, but However, No! as I mentioned this will break the pattern, and the code will slowly start to make a lot of noise.
Here we'll arrive at 2 good solutions:
[FIRST]:
inside Person.ts, remove the export keyword from beside the Person class, and by the end of the file, just write:
export = {
Person: {
Person,
PersonProps, // ERROR!
},
};
This is giving a compile-time error, for a very unknown logical reason, why that's not allowed!?
[SECOND]:
As I mentioned earlier, just let the PersonProps be property inside the class instances, so:
So the complete file will look the following:
Person.ts:
interface PersonProps {
name: string;
age: number;
}
class Person {
PersonProps: interface; // ERROR!
constructor(props: PersonProps) {
// props.name ...... props.age
this.PersonProps = PersonProps; // ERROR!
}
}
There are two compile-time errors here:
- An interface is not a type.
- You can't set an interface as a property within a class.
Now, finally, after writing this very long question:
- Do you have any idea of how to complete this solution?
- Do you have a better idea?
question from:
https://stackoverflow.com/questions/65651455/how-to-define-an-interface-as-a-class-property