Reputation: 298
I have the following two classes, where Circle
is an extension of Entity
. The constructor for Entity
uses a single argument which is supposed to be an Object, in order to allow customization of a new Entity
. Due to the more specific nature of the Circle
, I created a constructor with specific arguments, which I want to be less flexible. Here are the class declarations:
class Entity {
constructor(e) {
//use the attributes in the passed object to create a new Entity.
this.x = e.x; //position
this.y = e.y;
this.vY = this.vX = 0; //velocity
this.aX = this.aY = 0; //acceleration
}
}
class Circle extends Entity {
constructor(x, y, r, color) {
super({"x":x,"y":y}); //create Entity with given position;
this.r = r;
this.color = color;
}
}
I have also written a function addEntity(entity)
which is defined as follows:
addEntity(e) {
var ent_properties = Object.keys(e);
if(e.type) { //create a specific predefined Entity type, if thats what you want!
switch(e.type) {
case "circle":
try {
this.entities.push(new Circle(e.x, e.y, e.r, e.color));
} catch (err) { console.error(err); }
break;
default:
console.error("Invalid Entity Type Created: ");
console.error(e);
}
}
}
Obviously, there is still a good amount of work to be done here, and a lot of context that I left out (which isn't exactly relevant to the question at hand, but my issue that I bring to everyone here is this:
If I were to call
e.addEntity({
"type": "circle",
"x": x,
"y": y,
"r": 100,
"color": "black"
});
This creates a valid object, with every relevant value filled. However, let's say that I forgot to include "r"
, or instead of writing "r"
, I wrote "radius"
, what would be the best way to catch that? As of right now, it just creates a Circle
with this.r = undefined
.
Additionally, what is the best way to make sure that the object I give to addEntity
has all the necessary attributes, depending on the type of Entity
that I want to create? I want to be able to add MORE types, while also making sure that if I were to add those types, I could throw an error if the type of Entity
was not define correctly.
TL;DR: How do I quickly validate in my code that a constructor was run using all of the necessary arguments?
Upvotes: 0
Views: 29
Reputation: 370769
Iterating over an array of required properties and then checking hasOwnProperty
would work...
const requiredProps = ['type', 'x', 'y', 'r', 'color'];
// ...
// Test the argument:
if (requiredProps.some(prop => !e.hasOwnProperty(prop))) {
throw new Error('Required prop not found');
}
Or perhaps have baseProps
for the Entity
, and additional props for other subclasses:
const baseRequiredProps = ['type', 'x', 'y', 'r'];
// ...
class Entity {
constructor(e) {
const requiredProps = [...baseRequiredProps, ...(this.constructor.additionalRequiredProps || [])]
if (requiredProps.some(prop => !e.hasOwnProperty(prop))) {
throw new Error('Required prop not found');
}
// ...
class Circle extends Entity {
static additionalRequiredProps = ['color'];
In larger applications, I'd recommend approaching worries like this by using TypeScript instead, to force the caller to provide arguments of the desired type, without requiring any additional runtime code. It does take some getting used to, but it makes maintaining code a whole lot easier.
class Entity {
x: number;
y: number;
constructor(e: Entity) {
this.x = e.x;
this.y = e.y;
}
}
// works:
const e = new Entity({ x: 5, y: 10 });
class Circle extends Entity {
type = 'circle';
r: number;
color: string;
constructor(e: Circle) {
super(e);
this.type = e.type;
this.r = e.r;
this.color = e.color;
}
}
// fails:
const c = new Circle({
x: 5,
y: 7,
radius: 12,
color: 'black',
type: 'circle'
});
Since radius
was accidentally typed instead of r
, you get an error:
Upvotes: 1