The constructor function actually is what sits behind the class identifier. From a module point of view the author's implementation deals with a constructor function named PivateConstructorClass
which can not be directly invoked but features an additional create
method instead, which serves as factory function for creating PivateConstructorClass
instances.
And just for the sake of not wanting to allow the direct invocation of new PivateConstructorClass
, which still is possible (the invocation) since one can directly access the class constructor, one has to implement a lot of additional, and thus to be additionally tested code, which actually was not necessary if one just would expose a create
and an isInstance
method from an e.g. my-secretly-implemented-type
module.
Quoting the author … “As you can see, you get a JavaScript class with a private constructor without any obscure and unreliable hacks.” … This claim of cause is far from accurate. What one gets is what has been implemented. A public available and still callable constructor function which’s instantiation capacity got crippled due to throwing an excepting when being invoked without the symbol which I consider to be both … quoting the author again … “obscure and unreliable hacks”.
One should not make things more complicated than they really are. If one does not want others to access a class-constructor, one should not expose/export it.
A straightforward, lean and clean (without any smartassary) solution should look close to the next provided example code.
// begin "my-secretly-implemented-type" module.
// - class implementation protected by local/module scope.
class MySecretlyImplementedType {
constructor(prop1, prop2, prop3) {
Object.assign(this, { prop1, prop2, prop3});
}
}
// - the exported `MySecretlyImplementedType` instance checker.
export function isInstance(value) {
return (value instanceof MySecretlyImplementedType);
}
// - the exported `MySecretlyImplementedType` factory function.
export function create(...args) {
return new MySecretlyImplementedType(...args);
}
// end "my-secretly-implemented-type" module.
// another module's scope.
import {
isInstance as isMySecretlyImplementedType,
create as createMySecretlyImplementedType,
} from
'./my-secretly-implemented-type.js';
const myType =
createMySecretlyImplementedType('foo', 'bar', 'baz');
console.log({
myType,
isInstance: isMySecretlyImplementedType(myType),
});