使用Facebook Flow操作Map时调用push方法报错求助
解决Flow中Map.get()后的类型检查错误
嘿,这个问题我太熟了!Flow的静态分析没办法直接把Map.has(key)的检查和后续Map.get(key)的调用关联起来——哪怕你刚确认过key存在,它还是会揪着get可能返回undefined这一点不放。这是因为Flow会假设:在has和get之间,可能有其他代码(比如异步操作、外部函数调用)修改了这个Map,所以它严格遵循Map.get()的类型定义:返回值是T | undefined,不管你之前做了啥检查。
别担心,有几种实用的解决办法:
方案1:存变量+显式空检查(最安全)
把testMap.get(key)的结果存到变量里,再做一次空检查。这样Flow就能明确知道这个变量不是undefined了:
/* @flow */ let testMap: Map<string, Array<number>> = new Map(); let key: string = "testString"; if (!testMap.has(key)) { testMap.set(key, []) } const arr = testMap.get(key); if (arr) { arr.push(1); }
方案2:非空断言(快速但要谨慎)
如果你能100%确定,在has检查之后到get调用之间,没有任何代码会删除这个key,那可以用非空断言!告诉Flow:“我保证这个值不是undefined”:
/* @flow */ let testMap: Map<string, Array<number>> = new Map(); let key: string = "testString"; if (!testMap.has(key)) { testMap.set(key, []) } testMap.get(key)!.push(1); // 用!跳过undefined检查
⚠️ 注意:用这个方式等于手动关闭了Flow的类型检查,如果后续代码逻辑变动导致get真的返回undefined,Flow不会再给你提醒,所以只在你完全掌控代码逻辑的时候用。
方案3:重构代码,一次性完成获取/初始化(最优雅)
可以把“获取数组,不存在就初始化并存入Map”的逻辑封装成一行或者一个辅助函数,这样Flow能清晰追踪类型,代码也更整洁:
简洁版
/* @flow */ let testMap: Map<string, Array<number>> = new Map(); let key: string = "testString"; const arr = testMap.get(key) || (testMap.set(key, []), testMap.get(key)); arr.push(1);
可复用辅助函数版
/* @flow */ // 封装一个通用的获取/初始化Map条目函数 function getOrInitMapEntry<K, V>(map: Map<K, V>, key: K, init: () => V): V { const entry = map.get(key); if (entry) return entry; const newEntry = init(); map.set(key, newEntry); return newEntry; } let testMap: Map<string, Array<number>> = new Map(); let key: string = "testString"; const arr = getOrInitMapEntry(testMap, key, () => []); arr.push(1);
这种方式不仅解决了类型错误,还让代码更易维护,Flow也能完美识别类型。
总的来说,方案1和方案3是最稳妥的选择,方案2适合快速临时解决问题,但要注意潜在风险。
内容的提问来源于stack exchange,提问作者Valdemar Edvard Sandal Rolfsen
相关产品推荐
相关产品推荐

