在业务开发中,我们常常需要定义一些枚举值。随着业务逻辑的扩展,简单的枚举值往往会衍生出许多关联的字典。比如,或者需要定义一个类型对应的图标,在列表场景下,我们可能需要定义一个数组形式的字典,又或者希望使用 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'