UNPKG

@naturalcycles/js-lib

Version:

Standard library for universal (browser + Node.js) javascript

187 lines (186 loc) 5.69 kB
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; }