一、方法主体。使用的是 mix 方法,用法在下文
// Deep freezing function.
const deepFreeze = (obj: Record<string, any>) => {// Retrieve the definition inobjProperty name onconst propNames = Object.getOwnPropertyNames(obj);// Freeze attributes before freezing itselfpropNames.forEach(function (name) {const prop = obj[name];// IfpropIs an object,Freeze itif (typeof prop === 'object' && prop !== null) {deepFreeze(prop);}});// Freeze yourself(no-op if already frozen)return Object.freeze(obj);
};const isObject = (obj: any) => {return Object.prototype.toString.call(obj) === '[object Object]';
};export const deepMerge = (base: Record<string, any>,regionConfig: Record<string, any>,
) => {if (!isObject(base) || !isObject(regionConfig)) {return regionConfig ?? base;}return Object.keys({ ...base, ...regionConfig }).reduce((result, key) => {result[key] = deepMerge(base[key], regionConfig[key]);return result;}, {} as Record<string, any>);
};export function mix<T extends Record<string, any>>(base: T,regionConfig: Partial<T>,
) {const mixConfig = deepMerge(base, regionConfig);return deepFreeze(mixConfig) as T;
}
二、用法
1. 定义基准配置
export const baseConfig = {AModule: {hasTagFilter: false, // 是否提供标签filterapi: {searchData: {source: 0,},},},BModule: {...},CModule: {...},
};
2. 基于基准配置,覆写自定义配置
export const CONFIG = mix(baseConfig, {AModule: {hasTagFilter: true, // 覆写// 不涉及的 key 会自动使用读取 base 里的配置,这里不用再写},BModule: {...},CModule: {...},
} as Partial<typeof baseConfig>);
// !!!这里使用 Partial<typeof baseConfig>,如果有多写/错写,和 base 不一致,ts 会直接报错