如何将JSON反序列化为TypeScript的Map<TKey, TValue>实例?
如何将JSON反序列化为真正的Map<TKey, TValue>实例
JSON本身没有Map的原生表示,JSON.parse只会返回普通对象或数组,因此必须手动将解析后的对象转换为Map实例。以下是几种实用的实现方式:
1. 基础转换法(适用于简单键类型)
如果JSON是{"key1":"value1","key2":"value2"}这类字符串键结构,直接用Object.entries配合Map构造函数即可:
const jsonStr = '{"id":1,"name":"test"}'; const parsedObj = JSON.parse(jsonStr); const map = new Map<string, any>(Object.entries(parsedObj)); // 可正常调用Map的所有方法 map.forEach((value, key) => { console.log(`${key}: ${value}`); });
若键为数字类型,JSON解析后会转为字符串,需手动转换键类型:
const map = new Map<number, string>( Object.entries(parsedObj).map(([key, value]) => [parseInt(key, 10), value]) );
2. 自定义reviver函数(利用JSON.parse内置参数)
通过JSON.parse的第二个参数reviver,可在解析过程中直接将目标结构转为Map,适合嵌套场景中区分普通对象和Map:
function mapReviver(key: string, value: any): any { // 假设JSON中用"__type": "Map"标记需要转换的结构 if (typeof value === 'object' && value !== null && value.__type === 'Map') { return new Map(Object.entries(value.data)); } return value; } // 对应的JSON需提前添加类型标记 const jsonWithMap = '{"config": {"__type": "Map", "data": {"theme": "dark", "fontSize": 14}}}'; const result = JSON.parse(jsonWithMap, mapReviver); // result.config 是真正的Map实例
3. TypeScript泛型工具函数(保证类型安全)
封装泛型函数,确保转换后的Map类型符合预期,同时支持自定义键类型转换:
function jsonToMap<TKey extends string | number | symbol, TValue>( jsonStr: string, keyConverter?: (key: string) => TKey ): Map<TKey, TValue> { const parsed = JSON.parse(jsonStr); const entries = Object.entries(parsed).map(([key, value]) => { const convertedKey = keyConverter ? keyConverter(key as string) : (key as unknown as TKey); return [convertedKey, value as TValue]; }); return new Map(entries); } // 数字键示例 const numMap = jsonToMap<number, string>('{"1":"a","2":"b"}', key => parseInt(key, 10)); // 字符串键示例 const strMap = jsonToMap<string, number>('{"age":25,"score":90}');
4. 递归转换(处理嵌套Map结构)
如果JSON存在多层嵌套的Map,可通过递归函数批量处理:
function deepJsonToMap(obj: any): any { if (typeof obj !== 'object' || obj === null) return obj; // 识别标记字段转换为Map if (obj.__type === 'Map') { return new Map(Object.entries(obj.data).map(([k, v]) => [k, deepJsonToMap(v)])); } if (Array.isArray(obj)) { return obj.map(item => deepJsonToMap(item)); } return obj; } // 使用示例 const nestedJson = '{"user": {"__type": "Map", "data": {"name": "Alice", "settings": {"__type": "Map", "data": {"notifications": true}}}}}'; const result = deepJsonToMap(JSON.parse(nestedJson)); // result.user 和 result.user.get('settings') 均为Map实例
性能与C#配合建议
- 转换后的Map可直接利用
Map.forEach的性能优势,无需每次遍历都调用Object.entries;数据量极大时优先用基础转换法,减少额外函数调用开销。 - 由于你主要使用C#,序列化时可自定义JSON转换器(如Newtonsoft.Json或System.Text.Json),给Map/Dictionary类型字段添加
__type标记,方便前端自动识别转换。例如C#中System.Text.Json的自定义转换器:
public class MapConverter<TKey, TValue> : JsonConverter<Dictionary<TKey, TValue>> { public override Dictionary<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { throw new NotImplementedException(); } public override void Write(Utf8JsonWriter writer, Dictionary<TKey, TValue> value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteString("__type", "Map"); writer.WriteStartObject("data"); foreach (var kvp in value) { JsonSerializer.Serialize(writer, kvp.Key, options); JsonSerializer.Serialize(writer, kvp.Value, options); } writer.WriteEndObject(); writer.WriteEndObject(); } }
内容的提问来源于stack exchange,提问作者sbridewell
相关产品推荐
相关产品推荐

