2016-07-22 9 views
10

następujący kod zawężony w dół:dziwne `Metoda nie można nazwać na możliwie/null nieokreślonej value`

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

} 

& hellip; zawiedzie wpisać sprawdzanie przepływu z następującym komunikatem:

$ 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 

Jeśli odczyt linia: assert(true) jest wypowiedziało się, przepływ jest zadowolony!

Co daje?

PS: W przypadku gdy ktoś zastanawia się, moi .flowconfig, .babelrc i package.json pliki są nijakie:

.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" 
} 
} 
+0

To jest dokładnie to samo, co http://stackoverflow.com/questions/38479426/dynamic-type-tests-not-working-as-expected – vkurchatkin

+0

@vkurchatkin początkowo myślałem tak samo, ale nie jest. 'assert (true)' nie ma możliwości modyfikacji 'tree.children', więc Flow powinno to umożliwić. Różni się to od postu, do którego została przypisana metoda wywoływania metody, która ma potencjał dostępu do 'this'. Dopóki Flow nie uzna, że ​​funkcja 'assert' została stworzona w sposób, który pozwolił jej na uchwycenie zamknięcia względem lokalnej zmiennej' tree', nie wiem. –

Odpowiedz

4

Twoja sprawa została opisana jako here.

Flow nie może wiedzieć, że assert nie zmienia tree. Dodaj następujące linie do kodu i uruchom go - wystąpi błąd w czasie wykonywania, ponieważ funkcja assert ustawi tree.children na null po wywołaniu.

const root = new Node(1); 
const child = new Node(2); 

root.children = new Map([['child', child]]); 

assert =() => root.children = null; 

accessChildren(root); 

Tak, to dość dziwny kod, ale Flow nie wie, nie napiszesz go.

+0

dzięki za jasną i zwięzłą odpowiedź. To faktycznie sprawia, że ​​mnóstwo sensu! –

4

Inni wskazali właściwe wyjaśnienie. Na szczęście to działa:

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

} 

Również w przyszłych przepływów będzie tylko do odczytu właściwości i deklarując children jako właściwość tylko do odczytu w klasie Flow powinien móc zachować typ sprawdzić oryginalny kod.

Powiązane problemy