2016-07-22 20 views
10

Die folgende verengte-down-Code aufgerufen werden:seltsam `Methode kann nicht auf möglicherweise null/undefined 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; Ausbleibendem Förder Typ mit der folgenden Meldung Überprüfung:

$ 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 

Wenn die Zeile gelesen: assert(true) Kommentar gesetzt wird, den Ablauf zufrieden ist!

Was gibt?

PS: Falls sich jemand fragt, mein .flowconfig, .babelrc und package.json Dateien sind unscheinbar:

.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

Dies ist genau das gleiche wie http://stackoverflow.com/questions/38479426/dynamic-type-tests-not-working-as-expected – vkurchatkin

+0

@vkurchatkin zunächst dachte ich so viel, aber es ist nicht. 'assert (true)' hat keine Möglichkeit, 'tree.children' so zu ändern, dass Flow das erlaubt hätte. Dies unterscheidet sich von dem Beitrag, den Sie mit dem Aufruf einer Mitgliedsmethode verknüpfen, die Zugriff auf "this" hat. Wenn Flow nicht davon ausgeht, dass die Funktion 'assert' vielleicht so angelegt wurde, dass sie eine Schließung über die lokale Variable' tree' festhalten konnte, weiß ich nicht. –

Antwort

4

Ihr Fall wird beschrieben here.

Flow kann nicht wissen, dass assert die tree nicht ändert. Fügen Sie die folgenden Zeilen zu Ihrem Code hinzu und führen Sie ihn aus - Sie werden einen Laufzeitfehler haben, weil die assert-Funktion tree.children auf null setzt, wenn sie aufgerufen wird.

Ja, es ist ziemlich komisch Code, aber Flow weiß es nicht, Sie werden es nicht schreiben.

+0

danke für die klare und prägnante Antwort. Das macht wirklich Sinn! –

4

Andere haben auf die richtige Erklärung hingewiesen. Zum Glück funktioniert das:

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

} 

Auch in Zukunft fließen schreibgeschützte Eigenschaften und durch children als schreibgeschützte Eigenschaft in der Klasse deklarieren, sollte Fluss der Lage sein Typ den ursprünglichen Code zu erhalten überprüfen.