奇怪的`无法对可能为空/未定义的值调用方法`
weird `Method cannot be called on possibly null / undefined value`
以下缩小代码:
// @流动
'use strict';
import assert from 'assert';
class Node<V, E> {
value: V;
children: ?Map<E, Node<V,E>>;
constructor(value: V) {
this.value = value;
this.children = null;
}
}
function accessChildren(tree: Node<number, string>): void {
if (tree.children!=null) {
assert(true); // if you comment this line Flow is ok
tree.children.forEach( (v,k)=>{});
} else {
}
}
… 流类型检查失败并显示以下消息:
$ npm run flow
> simple-babel-serverside-node-only-archetype@1.0.0 flow /home/blah/blah/blah
> flow; test $? -eq 0 -o $? -eq 2
es6/foo.js:21
21: tree.children.forEach( (v,k)=>{});
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call of method `forEach`. Method cannot be called on possibly null value
21: tree.children.forEach( (v,k)=>{});
^^^^^^^^^^^^^ null
es6/foo.js:21
21: tree.children.forEach( (v,k)=>{});
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call of method `forEach`. Method cannot be called on possibly undefined value
21: tree.children.forEach( (v,k)=>{});
^^^^^^^^^^^^^ undefined
Found 2 errors
如果注释掉 assert(true)
行,流程就满足了!
什么给了?
PS: 如果有人想知道,我的 .flowconfig
、.babelrc
和 package.json
文件是不起眼的:
.flowconfig
$ cat .flowconfig
[options]
esproposal.class_static_fields=enable
.babelrc
$ cat .babelrc
{
"presets": ["es2015"],
"plugins": ["transform-object-rest-spread", "transform-flow-strip-types", "transform-class-properties"]
}
package.json
$ cat package.json
{
"name": "simple-babel-serverside-node-only-archetype",
"version": "1.0.0",
"description": "",
"main": [
"index.js"
],
"scripts": {
"build": "babel es6 --out-dir es5 --source-maps",
"build-watch": "babel es6 --out-dir es5 --source-maps --watch",
"start": "node es5/index.js",
"flow": "flow; test $? -eq 0 -o $? -eq 2"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-cli": "^6.6.5",
"babel-core": "^6.7.4",
"babel-plugin-transform-class-properties": "^6.10.2",
"babel-plugin-transform-flow-strip-types": "^6.8.0",
"babel-polyfill": "^6.7.4",
"babel-preset-es2015": "^6.9.0",
"babel-runtime": "^6.6.1",
"flow-bin": "^0.27.0"
},
"dependencies": {
"babel-plugin-transform-object-rest-spread": "^6.8.0",
"babel-polyfill": "^6.7.4",
"source-map-support": "^0.4.0"
}
}
您的案例描述为 here。
Flow 无法知道,assert
不会改变 tree
。
将以下行添加到您的代码中并 运行 它 - 您将遇到 运行 时间错误,因为断言函数将在调用时将 tree.children
设置为 null
。
const root = new Node(1);
const child = new Node(2);
root.children = new Map([['child', child]]);
assert = () => root.children = null;
accessChildren(root);
是的,很奇怪的代码,但是Flow不知道,你不会写的。
其他人指出了正确的解释。幸运的是这有效:
// @flow
'use strict';
import assert from 'assert';
class Node<V, E> {
value: V;
children: ?Map<E, Node<V, E>>;
constructor(value: V) {
this.value = value;
this.children = null;
}
}
function accessChildren(tree: Node<number, string>): void {
const children = tree.children; // save possibly mutable reference to local
if (children != null) {
assert(true); // if you comment this line Flow is ok
children.forEach((v, k) => {});
} else {
}
}
此外,未来 Flow 将具有只读属性,通过在 class 中将 children
声明为只读 属性,Flow 应该能够保留类型查看原码
以下缩小代码:
// @流动 'use strict';
import assert from 'assert';
class Node<V, E> {
value: V;
children: ?Map<E, Node<V,E>>;
constructor(value: V) {
this.value = value;
this.children = null;
}
}
function accessChildren(tree: Node<number, string>): void {
if (tree.children!=null) {
assert(true); // if you comment this line Flow is ok
tree.children.forEach( (v,k)=>{});
} else {
}
}
… 流类型检查失败并显示以下消息:
$ npm run flow
> simple-babel-serverside-node-only-archetype@1.0.0 flow /home/blah/blah/blah
> flow; test $? -eq 0 -o $? -eq 2
es6/foo.js:21
21: tree.children.forEach( (v,k)=>{});
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call of method `forEach`. Method cannot be called on possibly null value
21: tree.children.forEach( (v,k)=>{});
^^^^^^^^^^^^^ null
es6/foo.js:21
21: tree.children.forEach( (v,k)=>{});
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call of method `forEach`. Method cannot be called on possibly undefined value
21: tree.children.forEach( (v,k)=>{});
^^^^^^^^^^^^^ undefined
Found 2 errors
如果注释掉 assert(true)
行,流程就满足了!
什么给了?
PS: 如果有人想知道,我的 .flowconfig
、.babelrc
和 package.json
文件是不起眼的:
.flowconfig
$ cat .flowconfig
[options]
esproposal.class_static_fields=enable
.babelrc
$ cat .babelrc
{
"presets": ["es2015"],
"plugins": ["transform-object-rest-spread", "transform-flow-strip-types", "transform-class-properties"]
}
package.json
$ cat package.json
{
"name": "simple-babel-serverside-node-only-archetype",
"version": "1.0.0",
"description": "",
"main": [
"index.js"
],
"scripts": {
"build": "babel es6 --out-dir es5 --source-maps",
"build-watch": "babel es6 --out-dir es5 --source-maps --watch",
"start": "node es5/index.js",
"flow": "flow; test $? -eq 0 -o $? -eq 2"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-cli": "^6.6.5",
"babel-core": "^6.7.4",
"babel-plugin-transform-class-properties": "^6.10.2",
"babel-plugin-transform-flow-strip-types": "^6.8.0",
"babel-polyfill": "^6.7.4",
"babel-preset-es2015": "^6.9.0",
"babel-runtime": "^6.6.1",
"flow-bin": "^0.27.0"
},
"dependencies": {
"babel-plugin-transform-object-rest-spread": "^6.8.0",
"babel-polyfill": "^6.7.4",
"source-map-support": "^0.4.0"
}
}
您的案例描述为 here。
Flow 无法知道,assert
不会改变 tree
。
将以下行添加到您的代码中并 运行 它 - 您将遇到 运行 时间错误,因为断言函数将在调用时将 tree.children
设置为 null
。
const root = new Node(1);
const child = new Node(2);
root.children = new Map([['child', child]]);
assert = () => root.children = null;
accessChildren(root);
是的,很奇怪的代码,但是Flow不知道,你不会写的。
其他人指出了正确的解释。幸运的是这有效:
// @flow
'use strict';
import assert from 'assert';
class Node<V, E> {
value: V;
children: ?Map<E, Node<V, E>>;
constructor(value: V) {
this.value = value;
this.children = null;
}
}
function accessChildren(tree: Node<number, string>): void {
const children = tree.children; // save possibly mutable reference to local
if (children != null) {
assert(true); // if you comment this line Flow is ok
children.forEach((v, k) => {});
} else {
}
}
此外,未来 Flow 将具有只读属性,通过在 class 中将 children
声明为只读 属性,Flow 应该能够保留类型查看原码