This is a pretty nice use case; another way to make it more modular is to split the base component as say toggle.js and the different static properties as toggle-on.js, etc.. Then you can import and export them as components created by defineProperty. This really helps in testing but goes against the philosophy of using the static modifier.
I was working on a command-line application for some internal use and we had a problem testing it and rendering the default output. We wanted a structure hierarchy such that each command contains its description, usage example, flags and arguments. What I came up was using a CommandBase class to define the rudimentary interface (not TS, but in a way that was the purpose). Since this was internally open source, testing was a breeze as we had defined some base test cases.
Consider the following snipper from CommandBase.js:
class CommandBase {
constructor( args, flags ) {
this.args = args;
this.flags = flags;
}
run( additionalContext ) {
return this.tasks.run( {
args: this.args,
flags: this.flags,
...additionalContext
} );
}
}
module.exports = CommandBase;
Testing if the contributed commands were valid, we used instanceof. So:
class ExampleCommand extends CommandBase { ... }
In __tests__/blocks/example-command.js
...
const obj = new ExampleCommand();
expect( obj instanceof CommandBase ).to.be.true;
Coming to static modifiers, since we need to build a help text when the user enters the wrong number or arguments or explicitly asks for it, we added a static meta() function in the ExampleCommand class. This can be, as is evident, called without initializing a new instance and proved to be really helpful when we needed to get all the meta information: flags, commands, description, etc. as an object.
What you did was an example of namespacing the components. Similarly, say you have a module called MyNamespace with two classes: classOne and classTwo. You can do something like this:
src/MyNamespace/index.js
const ClassOne = require( './class-one.js' );
const ClassTwo = require( './class-two.js' );
class MyNamespace{
static ClassOne = () => ClassOne;
static ClassTwo = () => ClassTwo;
}
And then you can define class-one.js and class-two.js with whatever you want it to encapsulate. It makes the code a little more organized and clean.
Other times, I have used the static property to usually define the extra information about a class. An excellent use case is building a plugin-based architecture. The developers can extend from the PluginBase class and add the static meta() property to get information such as the version, etc.
If you create a complex data structure, making a custom .equals() makes sense. I usually make this as a static member for the class and then extend that into the object context by either binding or using .call().
I will add more use cases as and when I remember those.