Flow: Flow does not recognize early exit when checking MaybeTypes

Created on 12 Jan 2016  路  3Comments  路  Source: facebook/flow

I would expect flow to detect that this.p can not be null in the following case, but it gives the following warning: propertyx. Property cannot be accessed on possibly null value

type Point = {
  x: number,
  y: number,
};

export default class X {
  p: ?Point;

  do() {
    if (this.p == null) {
      return;
    }

    console.log(this.p.x);
  }
}

Most helpful comment

@tp see http://flowtype.org/docs/dynamic-type-tests.html#caveats for the explanation of this and a description of a workaround.

Going to close this since the issue is well known and documented with a workaround. Thanks!

All 3 comments

Hmm, the code provided doesn't error for me: http://tryflow.org/#80b6fc7e07bc8fc7f625c594018e7f92

Maybe your actual code is a little more complicated? A common error is something like

  do() {
    if (this.p == null) {
      return;
    }

    foo();

    console.log(this.p.x);
  }

Flow is worried that when you call foo() something might set this.p back to null, so it throws away its refinements. The usual workaround is using a local, like

  do() {
    var p = this.p;
    if (p == null) {
      return;
    }

    foo();

    console.log(p.x);
  }

I have tried to create a smaller test case which definitely fails here. Removing the call to Math.abs() fixes the issue.

Does Flow assume that the Math.abs call would mess with my instance?

/* @flow */

const STROKE_WIDTH = 4;

type Point = {
  x: number,
  y: number,
};

export default class RectangleHandler {
  ctx: CanvasRenderingContext2D;
  endCoordinates: ?Point;

  constructor(ctx: CanvasRenderingContext2D, color: string, pageScaleFactor: number, presentationId: number, pageId: number, attendeeId: number, filled: boolean) {
    this.ctx = ctx;
  }

  onMouseUp(x: number, y: number) {
    if (this.endCoordinates == null) {
      this.endDrawing();
      return;
    }

    let width = Math.abs(this.endCoordinates.x); // removing this line removes the Flow error
    console.log(this.endCoordinates.y);

    this.endDrawing();
  }

  endDrawing() {
    this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
  }
}

Error:

=> flow
test.js:25
 25:     console.log(this.endCoordinates.y);
                                         ^ property `y`. Property cannot be accessed on possibly null value
 25:     console.log(this.endCoordinates.y);
                     ^^^^^^^^^^^^^^^^^^^ null

test.js:25
 25:     console.log(this.endCoordinates.y);
                                         ^ property `y`. Property cannot be accessed on possibly undefined value
 25:     console.log(this.endCoordinates.y);
                     ^^^^^^^^^^^^^^^^^^^ undefined

@tp see http://flowtype.org/docs/dynamic-type-tests.html#caveats for the explanation of this and a description of a workaround.

Going to close this since the issue is well known and documented with a workaround. Thanks!

Was this page helpful?
0 / 5 - 0 ratings