The has()方法上Map https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has不充当类型保护方法 https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates on the Map
实例。所以打电话map.has(x)
has no 缩小 https://www.typescriptlang.org/docs/handbook/2/narrowing.html作用于map
,因此不会影响后续调用map.get(x)
.
有一个开放的功能请求:微软/TypeScript#13086 https://github.com/microsoft/TypeScript/issues/13086支持这一点,但它尚未实现,因为至少对于可变的、非ReadonlyMap
(see 使用 ReadonlyMap 类型 https://stackoverflow.com/q/50046573/2887218),事实是map.has(x)
is true
现在并不意味着将来会是true
永远。作为TS 团队开发负责人在此评论中提到 https://github.com/microsoft/TypeScript/issues/13086#issuecomment-524123373:“这么多,很多,很多,much比看起来更棘手,因为您还必须定义如何long the has
检查应该持续。”
任何适应这一点的改变都需要在两个方面都正确行事map.get()
下面几行:
const map = new Map([[1, { a: 1 }], [3, { a: 2 }]]);
if (map.has(2)) {
map.get(2).a; // should be okay
map.delete(2);
map.get(2).a; // should not be okay
}
现在它们都出错了,这很烦人,但很安全。
你可以合并你自己的类型保护has()
如果你愿意,也许像这样:
interface NarrowableMap<K, V> extends Map<K, V> {
has<P extends K>(k: P): this is { get(p: P): V } & this;
}
但这样就不会在两者上出错,这很方便,但不安全,尤其是在第二行。
const map = new Map([[1, { a: 1 }], [3, { a: 2 }]]) as
NarrowableMap<number, { a: number }>;
if (map.has(2)) {
map.get(2).a; // no error, that's good
map.delete(2);
map.get(2).a; // no error, that's bad
}
该语言当前没有办法将方法标记为重置控制流缩小。这会在财产重新分配时自动发生,并且delete
关键字,但映射操作不会触发此操作。
所以这就是为什么它不起作用。
最简单的重构就是放弃has
-then-get
并切换到get
-然后-验证。所以你可以这样做:
const v = map.get(2);
if (v !== undefined) { v.a }
或者你可以使用可选链接 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining使其更简洁:
const w = v?.a
const x = map.get(2)?.a
Playground 代码链接 https://www.typescriptlang.org/play?#code/MYewdgzgLgBAtgQwA4wLwzAUwO4wLLIAUA2sQIwA0MA3jAgFwxkwC+AulcQMxW0MwAmVmzYBKANwBYAFABLAGYxCiJADoAFggiEBo0TRkwj8ZKoDmmKDtGqE4mAHoHMCOpABXADYATGACNMGBAAawQAT0NjFVVvTE9LTGspaWMTNQsrXVt7Jxc3L18wEFgAoNCI6RYZGVkwKEwAJ3kEYECAOQQGhpBsBD94giQAHgBpKgA1AD4YTAAPerBvCHxkUYnp6kijTQghgAUZ+cxF5ZHJwmDGPdFGKHVZZYeaGAzCJCubmHHWGAAyGDuD2SVWkMjACDgmAgSBa7U63WwmF8m1BKWMoEgsBUaAwOBWSBI5F4dEYzHYnB4z34QnYYjoEC2qRgHS6PT6A1WYHccACDWJ-C5PMarEmyVSCiU0R21n0KKZUVMryydkZqWisXi9SSqoV6Us1myjJBMmN0gx0BgADccdElRIaopCNaAISodDuRaYeS1JGyq22Vgyc2wXDoS0AflsQfAFtmNsV+t0kYQQA