枚举定义业务字典

171 阅读2分钟

在业务开发中,我们常常需要定义一些枚举值。随着业务逻辑的扩展,简单的枚举值往往会衍生出许多关联的字典。比如,或者需要定义一个类型对应的图标,在列表场景下,我们可能需要定义一个数组形式的字典,又或者希望使用 key-object 形式避免从多个字典取值,这些形态各异的业务字典同时存在会给代码带来重复和混乱。

当我们需要变更或增删某个类型或者类型中的某个值时,需要同时修改多个字典,很容易出现遗漏和错误,尤其是当这些字典定义分布在不同的文件中。

对于使用者来说,散乱的字典定义也是一种负担。在业务中使用某个字典时,需要先查找已有的字典并理解其定义。如果已有字典不能完全满足需求,可能会有新的字典被定义,进一步增加业务字典的混乱程度。 我们可以实现一个工具函数,将一份定义转换成多种格式的字典。

首先考虑入参的格式。显然作为原始数据,入参必须能够包含完整的字典信息,包括键,值,所有扩展字段,甚至列表场景中的展示顺序。


const isPropertyKey = (val) => ['String', 'Number', 'Symbol'].includes(toRawType(val))

// Use lodash.pick instead
const pick =(target, keys) => {
    return keys.reduce((dict, key) => ({ ...dict, [key]: target[key] }), {})
}

function defineMap(defs, key, values) {

    if (typeof values === 'undefined') {
        return defs.map(def => def[key])
    }

    return defs.reduce((map, def) => {
        const _key = def[key]
        if (!isPropertyKey(_key)) return map

        const _val = Array.isArray(values) ? pick(def, values) : def[values]

        return { ...map, [_key]: _val }
    }, {})
}



const MusicTypeDefs = [
    {
        key:"pop",
        value: 1,
        name: '流行音乐',
        icon: 'pop.svg',
        style: { width: 100, height: 100, color: 'red' }
    },
    {
        key: 'rap',
        value: 2,
        name: '说唱音乐',
        icon: 'rap.svg',
        style: { width: 100, height: 100 }
    },
    {
        key: 'rock',
        value: 3,
        name: '摇滚音乐',
        icon: 'rock.svg',
        style: { width: 100, height: 100 }
    },
]

// list
const MusicTypeKeys = defineMap(MusicTypeDefs, 'key')
console.log(MusicTypeKeys, "MusicTypeKeys-")
const MusicTypeValues = defineMap(MusicTypeDefs, 'value')
console.log(MusicTypeValues, "MusicTypeValues-")
const MusicTypeNames = defineMap(MusicTypeDefs, 'name')
console.log(MusicTypeNames, "MusicTypeNames-")

const MusicTypeIcons = defineMap(MusicTypeDefs, 'icon')
console.log(MusicTypeIcons, "MusicTypeIcons-")

// map: key to value
const MusicTypeNameMaps = defineMap(MusicTypeDefs, 'key', 'name')
console.log(MusicTypeNameMaps, "MusicTypeNameMaps-")
const MusicTypeIconMaps = defineMap(MusicTypeDefs, 'key', 'icon')
console.log(MusicTypeIconMaps, "MusicTypeIconMaps-")
const MusicTypeName2IconMaps = defineMap(MusicTypeDefs, 'name', 'icon')
console.log(MusicTypeName2IconMaps, "MusicTypeName2IconMaps-")

const MusicTypeValue2IconMaps = defineMap(MusicTypeDefs, 'value', 'icon')
console.log(MusicTypeValue2IconMaps, "MusicTypeValue2IconMaps-")

const MusicTypeValue2NameMaps = defineMap(MusicTypeDefs, 'value', 'name')
console.log(MusicTypeValue2NameMaps, "MusicTypeValue2NameMaps-")


// console.log(MusicTypeIconMaps[MusicType.POP]) // 'pop.svg'
// console.log(MusicTypeName2IconMaps[MusicTypeDefs[2].icon]) // 'rock.svg'
// console.log(MusicTypeValue2IconMaps[MusicTypeDefs[1].value]) // 'rap.svg'
// console.log(MusicTypeValue2NameMaps[MusicTypeDefs[0]['value']]) // '流行音乐'

// map: key to values
const MusicTypeMaps = defineMap(MusicTypeDefs, 'key', ['value', 'name', 'icon', 'style'])

// console.log(MusicTypeMaps[MusicType.POP].name) // '流行音乐'
// console.log(MusicTypeMaps[MusicType.POP].icon) // 'pop.svg'

来源于:gist.github.com/jsonleex/12…