Подтвердить что ты не робот

Weird 'Метод не может быть вызван на возможно null/undefined value`

Следующий суженный код:

  //@течь   'использовать строгий';

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 {
    }

}

& hellip; не проходит проверку типа потока со следующим сообщением:

$ npm run flow

> [email protected] 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"
}
}
4b9b3361

Ответ 1

Ваше дело описано здесь.

Поток не может знать, что assert не изменяет tree. Добавьте в свой код следующие строки и запустите их - у вас будет ошибка времени выполнения, потому что при вызове функция assert будет устанавливать 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 не знает, вы его не напишете.

Ответ 2

Другие указали на правильное объяснение. К счастью, это работает:

// @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 будет иметь свойства только для чтения, и, объявив children как свойство только для чтения в классе, Flow сможет сохранить проверку типа исходного кода.