@naturalcycles/js-lib
Version:
Standard library for universal (browser + Node.js) javascript
187 lines (186 loc) • 5.69 kB
JavaScript
export function getEnumType(en) {
/*
* enum Foo { A = 1, B = 2 }
* becomes
* { "1": "A", "2": "B", "A": 1, "B": 2}
*
* enum Foo { A = "V1", B = "V2" }
* becomes
* { "V1": "A", "V2": "B", "A": "V1", "B": "V2"}
*/
const entries = Object.entries(en);
if (!entries.length)
return;
const [, value] = entries.pop();
let isNumberEnum = typeof value === 'number';
let isStringEnum = typeof value === 'string';
for (const [key, value] of entries) {
const isValueNumber = typeof value === 'number';
const isValueString = typeof value === 'string';
isStringEnum &&= isValueString;
isNumberEnum &&= isValueNumber || String(en[value]) === key;
if (!isStringEnum && !isNumberEnum)
break;
}
if (isNumberEnum)
return 'NumberEnum';
if (isStringEnum)
return 'StringEnum';
}
/**
* Returns all String keys of a number-enum.
*/
export function _numberEnumKeys(en) {
return Object.values(en).filter(k => typeof k === 'string');
}
/**
* Returns all Number values of a number-enum.
*/
export function _numberEnumValues(en) {
return Object.values(en).filter(k => typeof k === 'number');
}
/**
* Returns all String keys of a string-enum.
*/
export function _stringEnumKeys(en) {
return Object.keys(en);
}
/**
* Returns all String values of a string-enum.
*/
export function _stringEnumValues(en) {
// filtering here is unnecessary, but works as a safety in case Number-enum is passed
return Object.values(en).filter(k => typeof k === 'string');
}
/**
* Returns all number-enum "entries", where entry is a tuple of [key, value],
* where key is a String key, value is a Number value, typed as Enum itself.
*
* Doesn't work on String-enums!
*/
export function _numberEnumEntries(en) {
return Object.values(en)
.filter(k => typeof k === 'string')
.map(k => [k, en[k]]);
}
/**
* Like _numberEnumEntries, but reversed.
* So, keys are Numbers, values are Strings.
*/
export function _numberEnumEntriesReversed(en) {
return Object.values(en)
.filter(k => typeof k === 'string')
.map(k => [en[k], k]);
}
/**
* Like _numberEnumEntries, but as a Map.
* Keys are Strings, values are Numbers.
*/
export function _numberEnumAsMap(en) {
return new Map(Object.values(en)
.filter(k => typeof k === 'string')
.map(k => [k, en[k]]));
}
/**
* Like _numberEnumEntriesReversed, but as a Map.
* Keys are Numbers (actual Numbers, because it's a Map, not an Object), values are Strings.
*/
export function _numberEnumAsMapReversed(en) {
return new Map(Object.values(en)
.filter(k => typeof k === 'string')
.map(k => [en[k], k]));
}
/**
* Returns all string-enum "entries", where entry is a tuple of [key, value],
* where key is a String key, value is a String value, typed as Enum itself.
*
* Doesn't work on Number-enums!
*/
export function _stringEnumEntries(en) {
return Object.entries(en);
}
/**
* Like _stringEnumEntries, but keys and values are reversed.
*/
export function _stringEnumEntriesReversed(en) {
return Object.entries(en).map(([k, v]) => [v, k]);
}
/**
* Return String enum as Map (with the same keys and values).
*/
export function _stringEnumAsMap(en) {
return new Map(Object.entries(en));
}
/**
* Return String enum as Map, with keys and values reversed.
*/
export function _stringEnumAsMapReversed(en) {
return new Map(Object.entries(en).map(([k, v]) => [v, k]));
}
/**
* Allows to return a Number enum value (typed as Enum itself) based on it's String key.
* e.g:
* const v = SomeEnum['stringKey']
* // v is of type SomeEnum, which is of type Number
*
* Throws if value is not found!
*/
export function _numberEnumValue(en, k) {
const r = en[k];
if (!r)
throw new Error(`_numberEnumValue not found for: ${k}`);
return r;
}
/**
* _numberEnumKey, but allows to get/return undefined output.
*/
export function _numberEnumValueOrUndefined(en, k) {
return en[k];
}
/**
* Takes number or string enum input, returns normalized Enum output (Number).
* Only works for number enums.
*
* Throws if value is not found!
*/
export function _numberEnumNormalize(en, v) {
const r = _numberEnumNormalizeOrUndefined(en, v);
if (!r || !en[r])
throw new Error(`_numberEnumNormalize value not found for: ${v}`);
return r;
}
/**
* Same as _numberEnumNormalize, but allows to return undefined values.
*/
export function _numberEnumNormalizeOrUndefined(en, v) {
return typeof v === 'string' ? en[v] : v;
}
/**
* Returns a String key for given NumberEnum value, or undefined if not found.
*/
export function _numberEnumKeyOrUndefined(en, v) {
const key = en[v];
// This prevents passing a Key (not a Value) of enum here, which returns unexpected result (number, not string)
return typeof key === 'string' ? key : undefined;
}
/**
* Returns a String key for given NumberEnum value, throws if not found.
*/
export function _numberEnumKey(en, v) {
const key = en[v];
// This prevents passing a Key (not a Value) of enum here, which returns unexpected result (number, not string)
if (typeof key !== 'string')
throw new Error(`_numberEnumKey not found for: ${v}`);
return key;
}
export function _stringEnumKeyOrUndefined(en,
// v: T[keyof T] | undefined | null, // cannot make it type-safe :(
v) {
return Object.entries(en).find(([_, v2]) => v2 === v)?.[0];
}
export function _stringEnumKey(en, v) {
const r = _stringEnumKeyOrUndefined(en, v);
if (!r)
throw new Error(`_stringEnumKey not found for: ${v}`);
return r;
}