// МОЯ ФАНТАЗИЯ на тему, как должны выглядеть перечисления в нашем новом решении.
import {Enum} from "ts-jenum";
@Enum("text")
export class State {
static readonly NEW = new State("New");
static readonly ACTIVE = new State("Active");
static readonly BLOCKED = new State("Blocked");
private constructor(public text: string) {
super();
}
}
// Пример использования
console.log("" + State.ACTIVE); // Active
console.log("" + State.BLOCKED); // Blocked
console.log(State.values()); // [State.NEW, State.ACTIVE, State.BLOCKED]
console.log(State.valueOf("New")); // State.NEW
console.log(State.valueByName("NEW")); // State.NEW
console.log(State.ACTIVE.enumName); // ACTIVE
export function Enum(idProperty?: string) {
// tslint:disable-next-line
return function <T extends Function, V>(target: T): T {
if ((target as any).__enumMap__ || (target as any).__enumValues__) {
const enumName = (target as any).prototype.constructor.name;
throw new Error(`The enumeration ${enumName} has already initialized`);
}
const enumMap: any = {};
const enumMapByName: any = {};
const enumValues = [];
// Lookup static fields
for (const key of Object.keys(target)) {
const value: any = (target as any)[key];
// Check static field: to be instance of enum type
if (value instanceof target) {
let id;
if (idProperty) {
id = (value as any)[idProperty];
if (typeof id !== "string" && typeof id !== "number") {
const enumName = (target as any).prototype.constructor.name;
throw new Error(`The value of the ${idProperty} property in the enumeration element ${enumName}. ${key} is not a string or a number: ${id}`);
}
} else {
id = key;
}
if (enumMap[id]) {
const enumName = (target as any).prototype.constructor.name;
throw new Error(`An element with the identifier ${id}: ${enumName}.${enumMap[id].enumName} already exists in the enumeration ${enumName}`);
}
enumMap[id] = value;
enumMapByName[key] = value;
enumValues.push(value);
Object.defineProperty(value, "__enumName__", {value: key});
Object.freeze(value);
}
}
Object.freeze(enumMap);
Object.freeze(enumValues);
Object.defineProperty(target, "__enumMap__", {value: enumMap});
Object.defineProperty(target, "__enumMapByName__", {value: enumMapByName});
Object.defineProperty(target, "__enumValues__", {value: enumValues});
if (idProperty) {
Object.defineProperty(target, "__idPropertyName__", {value: idProperty});
}
// методы values(), valueOf и др потерялись во времени, но жили здесь когда-то.
Object.freeze(target);
return target;
};
}
// ПРИМЕЧАНИЕ: этот код примерно так выглядел, но что-то я из него потерял
export class Enumerable<T> {
constructor() {
const clazz = this.constructor as any as EnumStore;
if (clazz.__enumMap__ || clazz.__enumValues__ || clazz.__enumMapByName__) {
throw new Error(`It is forbidden to create ${clazz.name} enumeration elements outside the enumeration`);
}
}
static values<T>(): ReadonlyArray<T> {
const clazz = this as any as EnumStore;
if (!clazz.__enumValues__) {
throw new Error(`${clazz.name} enumeration has not been initialized. It is necessary to add the decorator @Enum to the class`);
}
return clazz.__enumValues__;
}
static valueOf<T>(id: string | number): T {
const clazz = this as any as EnumStore;
if (!clazz.__enumMap__) {
throw new Error(`${clazz.name} enumeration has not been initialized. It is necessary to add the decorator @Enum to the class`);
}
const value = clazz.__enumMap__[id];
if (!value) {
throw new Error(`The element with ${id} identifier does not exist in the $ {clazz.name} enumeration`);
}
return value;
}
static valueByName<T>(name: string): T {
const clazz = this as any as EnumStore;
if (!clazz.__enumMapByName__) {
throw new Error(`${clazz.name} enumeration has not been initialized. It is necessary to add the decorator @Enum to the class`);
}
const value = clazz.__enumMapByName__[name];
if (!value) {
throw new Error(`The element with ${name} name does not exist in the ${clazz.name} enumeration`);
}
return value;
}
get enumName(): string {
return (this as any).__enumName__;
}
toString(): string {
const clazz = this.constructor as any as EnumStore;
if (clazz.__idPropertyName__) {
const self = this as any;
return self[clazz.__idPropertyName__];
}
return this.enumName;
}
}
export function EnumType<T>(): IStaticEnum<T> {
return (<IStaticEnum<T>> Enumerable);
}
// где IStaticEnum это:
export interface IStaticEnum<T> {
new(): {enumName: string};
values(): ReadonlyArray<T>;
valueOf(id: string | number): T;
valueByName(name: string): T;
}
import {Enum, EnumType, IStaticEnum} from "ts-jenum";
@Enum("text")
export class State extends EnumType<State>() {
static readonly NEW = new State("New");
static readonly ACTIVE = new State("Active");
static readonly BLOCKED = new State("Blocked");
private constructor(public text: string) {
super();
}
}
// Пример использования
console.log("" + State.ACTIVE); // Active
console.log("" + State.BLOCKED); // Blocked
console.log(State.values()); // [State.NEW, State.ACTIVE, State.BLOCKED]
console.log(State.valueOf("New")); // State.NEW
console.log(State.valueByName("NEW")); // State.NEW
console.log(State.ACTIVE.enumName); // ACTIVE
К сожалению, не доступен сервер mySQL