This project is made to have an implementation of enum class similar in each language.
Or at least give a similar behaviour.
Also, the implementations use class inheritance in the `Enum` as well as their `CompanionEnum` counterpart.
The only location where it doesn't follow this is in the utility classes / files
like EnumHelper, EnumConstants and EnumExtension.
Note:
The usage of COMPANION_ENUM in the extension can be changed to
CompanionEnum, CompanionEnumWithParent,
CompanionEnumWithGrandParent or CompanionEnumWithGreatGrandParent.
And in C#, it uses the type system to its advantage (like for the ValueTuple).
(This may change once the implementation is made)
Here is a list of the related projects made by me
You can contribute to my projects in 2 different ways
The implementations are different across the different languages, but they should not change in their implementation (it's only the syntax that is different for the most part).
This project (currently published on NPM) is the one with the most manual labour to implement.
The basic usage can be:
Enum extension
Keep in mind that the Enumerable interface can also be used if the direct inheritance cannot be used.
But a custom implementation is required for them.
// Javascript
class Example extends Enum {}// Typescript (generic usage)
class Example extends Enum {}// Typescript (strict types)
class Example extends Enum<Ordinals, Names> {}// Typescript (strict specific types)
class Example<ORDINAL extends Ordinals = Ordinals, NAMES extends Names = Names,> extends Enum<ORDINAL, NAME> {}Companion enum
The companion enum implementation is a static field on the enum class named CompanionEnum
due to the fact there is no Annotation/Attribute usable in the language natively.
And in the case a custom implementation is needed, the classes are extensible.
Also, there is interfaces like CompanionEnumDeclaration should be declared.
// Javascript
class CompanionEnum_Example extends CompanionEnum {
static #instance
/** @private */constructor() { super(Example,) }
static get get() { return CompanionEnum_Example.#instance ??= new CompanionEnum_Example() }
}// Typescript (generic usage)
class CompanionEnum_Example extends CompanionEnum {
static #instance?: CompanionEnum_Example
private constructor() { super(Example,) }
public static get get() { return CompanionEnum_Example.#instance ??= new CompanionEnum_Example() }
}// Typescript (strict type usage)
class CompanionEnum_Example extends CompanionEnum<Example, typeof Example> {
static #instance?: CompanionEnum_Example
constructor() { super(Example,) }
static get get() { return CompanionEnum_Example.#instance ??= new CompanionEnum_Example() }
}Parenting enum enum
Implementing the enum with a "kind-of" inheritance can be used through the usage of
get parent, get grandParent and get greatGrandParent.
Javascript
class EnumExample extends Enum {}
class NullableParentingEnumExample extends EnumWithNullableParent {}
class ParentingEnumExample extends EnumWithParent {}
class NullableGrandParentingEnumExample extends EnumWithNullableGrandParent {}
class GrandParentingEnumExample extends EnumWithGrandParent {}
class NullableGreatGrandParentingEnumExample extends EnumWithNullableGreatGrandParent {}
class GreatGrandParentingEnumExample extends EnumWithGreatGrandParent {}Typescript
class EnumExample extends Enum {}
class NullableParentingEnumExample extends EnumWithNullableParent<EnumExample> {}
class ParentingEnumExample extends EnumWithParent<EnumExample> {}
class NullableGrandParentingEnumExample extends EnumWithNullableGrandParent<EnumExample, NullableParentingEnumExample> {}
class GrandParentingEnumExample extends EnumWithGrandParent<EnumExample, ParentingEnumExample> {}
class NullableGreatGrandParentingEnumExample extends EnumWithNullableGreatGrandParent<NullableGrandParentingEnumExample, NullableParentingEnumExample, EnumExample> {}
class GreatGrandParentingEnumExample extends EnumWithGreatGrandParent<GrandParentingEnumExample, ParentingEnumExample, EnumExample> {}Parenting companion extension
The parent companion enum do use inheritance, but not the direct inheritance.
Meaning that if Enum1 has a parent field Enum2. Enum2 cannot receive a Enum1 through its companion enum,
but the opposite is possible.
Enum1 can receive a Enum2 through its companion enum.
Javascript
class CompanionEnum_EnumExample extends CompanionEnum {
static #instance
constructor() { super(EnumExample,) }
static get get() { CompanionEnum_EnumExample.#instance ??= new CompanionEnum_EnumExample() }
}class CompanionEnum_ParentingEnumExample extends CompanionEnumWithParent {
static #instance
constructor() { super(EnumExample, ParentingEnumExample,) }
static get get() { CompanionEnum_ParentingEnumExample.#instance ??= new CompanionEnum_ParentingEnumExample() }
}class CompanionEnum_GrandParentingEnumExample extends CompanionEnumWithGrandParent {
static #instance
constructor() { super(EnumExample, ParentingEnumExample, GrandParentingEnumExample,) }
static get get() { CompanionEnum_GrandParentingEnumExample.#instance ??= new CompanionEnum_GrandParentingEnumExample() }
}Typescript
class CompanionEnum_EnumExample extends CompanionEnum<EnumExample, typeof EnumExample> {
static #instance?: CompanionEnum_EnumExample
private constructor() { super(EnumExample,) }
public static get get() { CompanionEnum_EnumExample.#instance ??= new CompanionEnum_EnumExample() }
}class CompanionEnum_ParentingEnumExample extends CompanionEnumWithParent<EnumExample, typeof EnumExample, ParentingEnumExample, typeof ParentingEnumExample> {
static #instance?: CompanionEnum_ParentingEnumExample
private constructor() { super(EnumExample, ParentingEnumExample,) }
public static get get() { CompanionEnum_ParentingEnumExample.#instance ??= new CompanionEnum_ParentingEnumExample() }
}class CompanionEnum_GrandParentingEnumExample extends CompanionEnumWithGrandParent<EnumExample, typeof EnumExample, ParentingEnumExample, typeof ParentingEnumExample, GrandParentingEnumExample, typeof GrandParentingEnumExample> {
static #instance?: CompanionEnum_GrandParentingEnumExample
private constructor() { super(EnumExample, ParentingEnumExample, GrandParentingEnumExample,) }
public static get get() { CompanionEnum_GrandParentingEnumExample.#instance ??= new CompanionEnum_GrandParentingEnumExample() }
}It also uses utility classes like the internal Helper
and the public EnumConstants in order to be accessible
outside the scope of the enums.
This implementation does work independently of the Kotlin implementation.
Meaning that a enum class in Kotlin would not work with a enum in Java.
But an adaptor could be used in these cases.
Also, if you intend to use this implementation with Kotlin directly,
then use the Kotlin implementation since it is more optimized for it.
Simple example
import github.io.joookiwi.java.enumerable.Enumerable;
enum Example implements Enumerable<Example> {}import github.io.joookiwi.java.enumerable.Enum;
class Example extends Enum<Example> {}Parenting enum
You can use the interface directly when implementing the enum directly
import github.io.joookiwi.java.enumerable.Enumerable;
enum EnumExample implements Enumerable<EnumExample> {}import github.io.joookiwi.java.enumerable.EnumerableWithParent;
import org.jetbrains.annotations.Nullable;
enum ParentingEnumExample
implements EnumerableWithParent<EnumExample> {
private final EnumExample parent;
ParentingEnumExample() { this(null); }
ParentingEnumExample(@Nullable EnumExample parent) { this.parent = parent; }
@Override public final @Nullable EnumExample getParent() { return parent; }
}import github.io.joookiwi.java.enumerable.EnumerableWithGrandParent;
import org.jetbrains.annotations.Nullable;
enum GrandParentingEnumExample
implements EnumerableWithGrandParent<EnumExample, ParentingEnumExample> {
private final ParentingEnumExample parent;
private final EnumExample grandParent;
GrandParentingEnumExample() { this(null, null); }
GrandParentingEnumExample(@Nullable ParentingEnumExample parent) { this(parent, null); }
GrandParentingEnumExample(@Nullable ParentingEnumExample parent, @Nullable EnumExample grandParent) {
this.parent = parent;
this.grandParent = grandParent;
}
@Override public final @Nullable ParentingEnumExample getParent() { return parent; }
@Override public final @Nullable EnumExample getGrandParent() { return grandParent; }
}Or you can use the "indirect" inheritance when using a class.
Of course, the interface is still possible, but less recommended.
import github.io.joookiwi.java.enumerable.Enum;
class EnumExample extends Enum<EnumExample> {
private EnumExample() { super(); }
}import github.io.joookiwi.java.enumerable.EnumeWithParent;
import org.jetbrains.annotations.Nullable;
class ParentingEnumExample
extends EnumWithParent<ParentingEnumExample, EnumExample> {
private ParentingExample() { super(); }
private ParentingExample(EnumExample parent) { super(parent); }
}import github.io.joookiwi.java.enumerable.EnumWithGrandParent;
import org.jetbrains.annotations.Nullable;
class GrandParentingEnumExample
extends EnumeWithGrandParent<GrandParentingEnumExample, ParentingEnumExample, EnumExample> {
private ParentingExample() { super(); }
private ParentingExample(@Nullable ParentingEnumExample parent) { super(parent); }
private ParentingExample(@Nullable ParentingEnumExample parent, @Nullable EnumExample grandParent) { super(parent, grandParent); }
}This implementation does work independently of the Java implementation.
Meaning that a enum in Java would not work with a enum class in Kotlin.
But an adaptor could be used in these cases.
Also, if you intend to use this implementation with Java directly,
then use the Java implementation since it is more optimized for it.
Simple example
enum Example {}import org.github.joookiwi.kotlin.enumerable.Enum
class Example: Enum()Parenting enum
You can use the interface directly when implementing the enum directly
import org.github.joookiwi.kotlin.enumerable.Enumerable
enum EnumExample: Enumerable<EnumExample>import org.github.joookiwi.kotlin.enumerable.EnumerableWithParent
enum ParentingEnumExample(
override val parent: EnumExample? = null,
): EnumerableWithParent<ParentingEnumExample, EnumExample>import org.github.joookiwi.kotlin.enumerable.EnumerableWithGrandParent
enum GrandParentingEnumExample(
override val parent: ParentingEnumExample? = null,
override val grandParent: EnumExample? = null,
): EnumerableWithGrandParent<GrandParentingEnumExample, ParentingEnumExample, EnumExample>Or you can use the "indirect" inheritance when using a class.
Of course, the interface is still possible, but less recommended.
import org.github.joookiwi.kotlin.enumerable.Enum
class EnumExample: Enum<EnumExample>()import org.github.joookiwi.kotlin.enumerable.EnumWithParent
class ParentingEnumExample(
override val parent: EnumExample? = null,
): EnumWithParent<ParentingEnumExample, EnumExample>(parent)import org.github.joookiwi.kotlin.enumerable.EnumWithGrandParent
class GrandParentingEnumExample(
override val parent: ParentingEnumExample? = null,
override val grandParent: EnumExample? = null,
): EnumWithGrandParent<GrandParentingEnumExample, ParentingEnumExample, EnumExample>(parent, grandParent)This implementation is only in a concept phase.
It may change at any time depending on how it can really be used in PHP.
Simple example
use joookiwi\enumerable\EnumerableTrait;
enum Example {
use EnumerableTrait<Example>;
}use joookiwi\enumerable\Enum;
class Example extends Enum<Example> {}Parenting enum
Since the PHP implementation is only in concept phase, this part may be incomplete
or not compilable.
But you can use the "indirect" inheritance when using a class.
use joookiwi\enumerable\Enum;
class EnumExample extends Enum<EnumExample> {
private function __construct() { parent::__construct(); }
}use joookiwi\enumerable\EnumeWithParent;
class ParentingEnumExample
extends EnumWithParent<ParentingEnumExample, EnumExample> {
private function __construct(parent: EnumExample|null = null) { parent::__construct(parent); }
}use joookiwi\enumerable\EnumWithGrandParent;
class GrandParentingEnumExample
extends EnumeWithGrandParent<GrandParentingEnumExample, ParentingEnumExample, EnumExample> {
private ParentingExample(ParentingEnumExample|null parent = null, EnumExample|null grandParent = null) { parent::__construct(parent, grandParent); }
}This implementation is only in a concept phase, but it has great features to use.
Keep in mind that extension function can be used for the already existing enums.
It may change at any time depending on how it can really be used in C#.
Simple example
enum Example {}using joookiwi.enumerable;
class Example: Enum<Example> {}Parenting enum
Or you can use the "indirect" inheritance when using a class.
Of course, the interface is still possible, but less recommended.
using joookiwi.enumerable;
class EnumExample: Enum<EnumExample> {
private EnumExample(): base() {}
}using joookiwi.enumerable;
class ParentingEnumExample:
Enum<ParentingEnumExample, EnumExample?> {
private ParentingExample(): base() {}
private ParentingExample(EnumExample? parent): base(parent) {}
}using joookiwi.enumerable;
class GrandParentingEnumExample:
Enum<GrandParentingEnumExample, ParentingEnumExample?, EnumExample?> {
private ParentingExample(): base() {}
private ParentingExample(ParentingEnumExample? parent): base(parent) {}
private ParentingExample(ParentingEnumExample? parent, EnumExample? grandParent): base(parent, grandParent) {}
}And the non-nullable can be used instead
using joookiwi.enumerable;
class ParentingEnumExample:
Enum<ParentingEnumExample, EnumExample> {
private ParentingExample(): base() {} // This will throw an exception
private ParentingExample(EnumExample parent): base(parent) {}
}using joookiwi.enumerable;
class GrandParentingEnumExample:
Enum<GrandParentingEnumExample, ParentingEnumExample, EnumExample> {
private ParentingExample(t): base() {} // This will throw an exception
private ParentingExample(ParentingEnumExample parent): base(parent) {} // This will throw an exception
private ParentingExample(ParentingEnumExample parent, EnumExample grandParent): base(parent, grandParent) {}
}| JS / TS version | Date | Quick note |
|---|---|---|
| 3.10.0 | August 12th, 2025 | collection ( |
| 3.9.0 | January 8th, 2025 | 2025 update, collection ( |
| 3.8.2 | December 12th, 2024 | collection ( |
| 3.8.1 | November 19th, 2024 | collection ( |
| 3.8.0 | November 7th, 2024 | collection ( |
| 3.7.0 | October 8th, 2024 | collection ( |
| 3.6.3 | August 15th, 2024 | collection ( |
| 3.6.2 | July 23rd, 2024 | collection ( |
| 3.6.1 | July 21st, 2024 | collection ( |
| 3.6.0 | July 21st, 2024 | collection ( |
| 3.5.0 | March 31st, 2024 | Addition of type to the dependency, Update to the documentation across the project, Addition of some future plan |
| 3.4.0 | February 19th, 2024 | 2024 update, Formatting across the whole project, collection ( |
| 3.3.1 | December 23rd, 2023 | collection ( |
| 3.3.0 | December 4th, 2023 | collection ( |
| 3.2.0 | September 28th, 2023 | collection ( Change of the exception hierarchy to be only toward the Javascript instead of Java-like |
| 3.1.0 | September 8th, 2023 | collection ( |
| 3.0.0 | August 14th, 2023 | Big changes to make the CompanionEnum more extensible via its protected methods |
| 2.7.0 | July 27th, 2023 | collection ( |
| 2.6.1 | July 26th, 2023 | Fix on the [Symbol.iterator]() that gave an error since it uses the yield* |
| 2.6.0 | July 23rd, 2023 | collection ( |
| 2.5.1 | July 14th, 2023 | The file EnumHelper was not exported |
| 2.5.0 | July 14th, 2023 | New Enum inheritor were added (parent, grandparent and great-grandparent with their nullable counterpart), Relocation & separation of the helper methods in its own folder |
| 2.4.2 | July 4th, 2023 | The file EnumHelper was exported as a type instead of directly |
| 2.4.1 | July 4th, 2023 | The files were not exported in the index file |
| 2.4.0 | July 3rd, 2023 | The dependency of collection is now a standalone package |
| 2.3.0 | June 18th, 2023 | New and renaming of some methods in collection (see the release note) |
| 2.2.3 | June 13th, 2023 | Fix on the collection when receiving receiving a Set or Array of 1 |
| 2.2.2 | June 12th, 2023 | Fix on the reverse order of the enum fields initialization |
| 2.2.1 | June 12th, 2023 | Fix of this[0] not set when receiving an array of 1 |
| 2.2.0 | June 12th, 2023 | New join, toWeakSet, reverse & hasNull in collection |
| 2.1.1 | June 8th, 2023 | Fix on the package.json file |
| 2.1.0 | June 6th, 2023 | Change from absolute imports to relative one (for better dependant utilisation) |
| 2.0.0 | February 2nd, 2023 | Change from static methods implementation to a companion enum implementation |
| 1.2.0 | Novembre 20th, 2022 | New filterByIndex & find in collection |
| 1.1.0 | November 19th, 2022 | New has, join, filter in the collection |
| 1.0.6 | November 12nd, 2022 | Addition of some forgotten types to be exported |
| 1.0.5 | November 11st, 2022 | The first version (after few tentative of publishing it) |