TypeScript + Map实现一个公共数据管理模块DataMap

在大型中后台项目开发中,尤其是在使用React进行开发时,我们会遇到很多下拉框数据、多选框数据、或者编码中多处使用到的业务型公共映射表。为了便于维护,可以把这些数据都集中放到一个模块中,而不是分散的写在各个地方。

实现思路

我们定义一个IMapExtra接口扩展一下Map实例,建立两个类MapExtraDataMapMapExtra是为了在使用数据时更方便获取Map类型数据。最后把map(数据映射)都存储在DataMap类的成员中。

开始

首先我们创建一个DataMap.ts文件用于公共数据管理的模块,并在里面创建一个MapExtra类实现IMapExtra接口,MapExtra功能主要是对原生Map进行一个简单的封装。原因是我们需要这个MapExtra实例来存储数据并可更方便的使用.get直接获取到对应的数据项。

DataMap.ts

import * as utils from '@/utils';

type MapType = Array<[T, T]>;
interface IMapExtra {
    map: Map;
    has:  ( key: string) => boolean;
    get: ( key: string) => string| number;
    getOptions: () => TYPE.IOption[];
}
class MapExtra  implements IMapExtra {
    public map;
    private _map;
    public constructor( map: MapType) {
        this._map = new Map(map);
        this.map = new Map(map);
    }

    public getOptions: IMapExtra['getOptions']  = () =>  utils.mapToOption(this._map);
    public has: IMapExtra['has'] = ( key) => this._map.has(key);
    public get: IMapExtra['get'] = ( key) => this._map.get(key) ?? key;
}

同时上面增加了一个getOptions方法更方便的拿到对应当前数据的下拉框结构,当然这里还可以扩展map转其他结构的数据。

mapToOption方法和下拉框结构接口的细节:

import * as TYPE from '@/interface';
//map 转换成 select option型数组
export const mapToOption = function(map: Map): TYPE.IOption[] {
    const option = [];
    for (const [k, v] of map) {
        option.push({label: v, value: k});
    }
    return option;
};
interface中导出IOption
export interface IOption {
    label: string | React.ReactNode;
    value: T;
    name?: string | number;
}

接下来继续在文件中创建两个FC、LC对象和DataMap类,把要存储的数据通过MapExtra实例化后存到对应属性中:

...
const FC = {
    category: new MapExtra([
        ['product',  '产品'],
        ['marketplace', '平台'],
    ]),
    timeUnit: new MapExtra([
        ['month',  '月度'],
        ['quarter', '季度'],
        ['year', '年度'],
    ]),
};

const LC = {
    remarkAction: new MapExtra([
        ['created',  '创建'],
        ['edited', '修改'],
        ['remark', '备注']
    ]),

    infoStatusMap: new MapExtra([
        ['normal', '正常'],
        ['invalid', '作废']
    ])
};


class DataMap {
    private _maps: Record> = {
        LC,
        FC
    };

    public getMapsLC: () => Record = () => {
        return this._maps.LC;
    };
    public getMapsFC: () => Record = () => {
        return this._maps.FC;
    };
}

const dataMap =  new DataMap();
export const getMapsLC = dataMap.getMapsLC();
export const getMapsFC = dataMap.getMapsFC();

DataMap是主要的用于管理整个数据模块,并导出DataMap对应模块的该实例方法,getMapsXXX其实就是对外提供直接获取对应XXX的数据模块。

成员_maps通过对象形式区分模块直接导出LC业务模块的dataMap实例,当后续新增业务模块时也是一样的需要新建对应的获取成员方法和导出。

这里_maps是定义为了一个私有成员,其实不是真正意义上的私有成员,_maps属性还是可以通过实例上获取到的。

最后

下面我们来使用这些数据,如获取一个下拉数据数组:
1.

import { getMapsLC } from '@/libs/DataMap';

console.log(getMapsFC.timeUnit.getOptions())

2.

//antd下拉框配置
 {
                        name: 'action',
                        label: '选择你的类型',
                        component: {
                            mode: 'multiple',
                            type: 'select',
                            options:getMapsLC.remarkAction.getOptions(),
                            placeholder: '请选择一项'
                        }
},



//antd映射出对应的值
        {
            title: '表格某一列',
            width: 100,
            dataIndex: 'action',
            render: (text: string) => getMapsLC.remarkAction.get(text)
        },

导入getMapsLC之后,getMapsLC.remarkAction.get(XXX) 直接就能获取到对应数据,getMapsLC.remarkAction.map则是直接取出一个map型的数据,并且可通过mapToOption转为下拉框数据的值。

完整代码:

import * as utils from '@/utils';

type MapType = Array<[T, T]>;
interface IMapExtra {
    map: Map;
    has:  ( key: string) => boolean;
    get: ( key: string) => string| number;
    getOptions: () => TYPE.IOption[];
}
class MapExtra  implements IMapExtra {
    public map;
    private _map;
    public constructor( map: MapType) {
        this._map = new Map(map);
        this.map = new Map(map);
    }

    public getOptions: IMapExtra['getOptions']  = () =>  utils.mapToOption(this._map);
    public has: IMapExtra['has'] = ( key) => this._map.has(key);
    public get: IMapExtra['get'] = ( key) => this._map.get(key) ?? key;
}


const FC = {
    category: new MapExtra([
        ['product',  '产品'],
        ['marketplace', '店铺'],
    ]),
    level: new MapExtra([
        ['primary',  '一级分类'],
        ['secondary', '二级分类']
    ]),
    timeUnit: new MapExtra([
        ['month',  '月度'],
        ['quarter', '季度'],
        ['year', '年度'],
    ]),
};

const LC = {
    remarkAction: new MapExtra([
        ['created',  '创建'],
        ['edited', '修改'],
        ['remark', '手动备注']
    ]),

    infoStatusMap: new MapExtra([
        ['normal', '正常'],
        ['invalid', '已作废']
    ])
};


class DataMap {
    private _maps: Record> = {
        LC,
        FC
    };

    public getMapsLC: () => Record = () => {
        return this._maps.LC;
    };
    public getMapsFC: () => Record = () => {
        return this._maps.FC;
    };
}

const dataMap =  new DataMap();
export const getMapsLC = dataMap.getMapsLC();
export const getMapsFC = dataMap.getMapsFC();

你可能感兴趣的:(typescript前端map)