动态类型测试未按预期工作
dynamic type tests not working as expected
这是一个SSCCE。
我有一个地图容器 class,其中一个内部 Map
是根据需要使用第一个被调用的 set
方法创建的:
// @flow
'use strict';
class MapContainer {
map: ?Map<any, any>;
constructor() {
this.map=null;
}
set(key: any, value: any): ?any {
if (this.map===null) {
this.map = new Map();
}
let prevValue: ?any;
if (this.map!=null) { // first check
prevValue = this.map.get(key);
}
if (this.map!=null) { // second check
this.map.set(key, value);
}
return prevValue;
}
}
exports.MapContainer = MapContainer;
以上代码通过了 npm run flow
,没有任何警告。
但是,如果我将两个 if (this.map!=null)
支票合并为一个:
// @flow
'use strict';
class MapContainer {
map: ?Map<any, any>;
constructor() {
this.map=null;
}
set(key: any, value: any): ?any {
if (this.map===null) {
this.map = new Map();
}
let prevValue: ?any;
if (this.map!=null) { // merged check
prevValue = this.map.get(key);
this.map.set(key, value);
}
return prevValue;
}
}
exports.MapContainer = MapContainer;
… 然后 运行 流程失败并显示以下消息:
es6/map-container.js:19
19: this.map.set(key, value);
^^^^^^^^^^^^^^^^^^^^^^^^ call of method `set`. Method cannot be called on possibly null value
19: this.map.set(key, value);
^^^^^^^^ null
es6/map-container.js:19
19: this.map.set(key, value);
^^^^^^^^^^^^^^^^^^^^^^^^ call of method `set`. Method cannot be called on possibly undefined value
19: this.map.set(key, value);
^^^^^^^^ undefined
... 这完全没有意义,因为第 19 行的访问:
this.map.set(key,value)
… 仍然在检查范围内:
if (this.map!=null)
什么给了?
问题是调用 get
方法会使优化无效。如果 get
将 this.map
设置为 null
怎么办? Flow 无从知晓,所以它会假设最坏的情况。您可以执行以下操作:
class MapContainer {
map: ?Map<any, any>;
constructor() {
this.map=null;
}
set(key: any, value: any): ?any {
if (!this.map) {
this.map = new Map();
}
const map = this.map;
let prevValue: ?any;
if (this.map!=null) {
prevValue = map.get(key);
map.set(key, value);
}
return prevValue;
}
}
这是一个SSCCE。
我有一个地图容器 class,其中一个内部 Map
是根据需要使用第一个被调用的 set
方法创建的:
// @flow
'use strict';
class MapContainer {
map: ?Map<any, any>;
constructor() {
this.map=null;
}
set(key: any, value: any): ?any {
if (this.map===null) {
this.map = new Map();
}
let prevValue: ?any;
if (this.map!=null) { // first check
prevValue = this.map.get(key);
}
if (this.map!=null) { // second check
this.map.set(key, value);
}
return prevValue;
}
}
exports.MapContainer = MapContainer;
以上代码通过了 npm run flow
,没有任何警告。
但是,如果我将两个 if (this.map!=null)
支票合并为一个:
// @flow
'use strict';
class MapContainer {
map: ?Map<any, any>;
constructor() {
this.map=null;
}
set(key: any, value: any): ?any {
if (this.map===null) {
this.map = new Map();
}
let prevValue: ?any;
if (this.map!=null) { // merged check
prevValue = this.map.get(key);
this.map.set(key, value);
}
return prevValue;
}
}
exports.MapContainer = MapContainer;
… 然后 运行 流程失败并显示以下消息:
es6/map-container.js:19
19: this.map.set(key, value);
^^^^^^^^^^^^^^^^^^^^^^^^ call of method `set`. Method cannot be called on possibly null value
19: this.map.set(key, value);
^^^^^^^^ null
es6/map-container.js:19
19: this.map.set(key, value);
^^^^^^^^^^^^^^^^^^^^^^^^ call of method `set`. Method cannot be called on possibly undefined value
19: this.map.set(key, value);
^^^^^^^^ undefined
... 这完全没有意义,因为第 19 行的访问:
this.map.set(key,value)
… 仍然在检查范围内:
if (this.map!=null)
什么给了?
问题是调用 get
方法会使优化无效。如果 get
将 this.map
设置为 null
怎么办? Flow 无从知晓,所以它会假设最坏的情况。您可以执行以下操作:
class MapContainer {
map: ?Map<any, any>;
constructor() {
this.map=null;
}
set(key: any, value: any): ?any {
if (!this.map) {
this.map = new Map();
}
const map = this.map;
let prevValue: ?any;
if (this.map!=null) {
prevValue = map.get(key);
map.set(key, value);
}
return prevValue;
}
}