Reputation: 55
I'm trying to write a JavaScript class constructor that can accept multiple options (just like some command-line tools, e.g. OpenSSL). For example:
class myClass {
constructor(pathOrSize, isPublic) {
// Receive an file path
if (typeof pathOrSize === 'string') {
if (isPublic) {
// Read public key file
this.public = ...
} else {
// Read private key file, and then generate public key instance
this.private = ...
this.public = ...
}
} else if (typeof pathOrSize === 'number') {
// Create a new key pair based on the given size
this.private = ...
this.public = ...
} else {
// Throw an error
}
}
// Use this.public (or this.private, if provided) to encrypt/decrypt message
}
When the class is instantiated, this.public
is required, but this.private
is optional. The conditional logic guarantees that if this.public
is not provided, an error will be thrown.
For the first parameter pathOrSize
, there are two possible input types so I use an if-else here to check the type. Then if it's string
, based on the value of isPublic
, we will get two more different scenarios that need to be handled. In my case, there are more options, which make the code snippet above looks even worse. It works, but it's verbose and hard to read :(
Given the fact that JavaScript doesn't support overloading (like Java) and pattern matching (like Rust), what's the most elegant or efficient way to handle situations like this?
Thanks for any solutions or thoughts!
Upvotes: 0
Views: 69
Reputation: 350270
A typical way to differentiate between parameters, is to provide an alternative, static function to create an instance. This is how it is done for some native classes. For instance, Array
has Array.of
, Array.from
, and Object
has Object.fromEntries
, Object.create
, ...
If we follow that pattern, your example code could become:
class MyClass {
static fromFile(path, isPublic=true) {
// read key file
const content = ...
// Pass the appropriate arguments to constructor
return isPublic ? new this(null, content) : new this(content);
}
static fromSize(size) {
// Create new key pairs based on the given size
const privateKey = ...
const publicKey = ...
return new this(privateKey, publicKey);
}
// Constructor is dumb: it has little logic
constructor(privateKey, publicKey) {
// If no public key is given, produce it from the private key
if (publicKey === undefined) {
if (privateKey === undefined) throw Error("must provide at least one key");
// Generate public key instance from private key
publicKey = ...
}
this.privateKey = privateKey ?? null; // turn undefined into null
this.publicKey = publicKey;
}
}
// Example calls:
let x = MyClass.fromFile("/testPublic.key");
let y = MyClass.fromSize(5);
let z = new MyClass("a", "b");
Upvotes: 1