Tharaka Wijebandara
Tharaka Wijebandara

Reputation: 8065

Flow type refinement doesn't work if check null/undefined through another vairable

In the following example (or on flow.org/try) type refinement doesn't seem to work when we check null/undefined via another variable.

type Position = {|
  x: number,
  y: number
|}

function anotherCondition(): bool{
  return true;
}

function getIt(): ?Position{
  return {x:7, y: 8}
}

function setIt(p:Position){
}

const pos = getIt();
const isOk = pos && anotherCondition();
isOk && setIt(pos)

But if we do it inline without isOk variable, it works fine. But I have several places to check this condition and using a variable like isOk make it less verbose. Is there any way to make it work? or am I missing something here?

Upvotes: 0

Views: 441

Answers (2)

user6445533
user6445533

Reputation:

Instead of relying on refinements, which are evidently frequently invalidated, you rather should define a union type that reflects both cases:

// @flow

type Position = {|
  x: number,
  y: number
|} | null

function anotherCondition(): bool{
  return true;
}

function getIt(): Position {
  const r = Math.random();
  return r <= 0.5 ? {x:7, y: 8} : null;
}

function setIt(p:Position){
  if (p) {}
  else {}
}

const pos = getIt();
setIt(pos);

Now, however, you have to take into account the different cases within the functions that except such a union type. This should still be more DRY.

I think you should avoid maybe types whenever possible and use the more accurate union types instead.

Upvotes: 1

MichaelDeBoey
MichaelDeBoey

Reputation: 2385

The problem is that your getIt function returns an optional Position, which means that flow doesn't know if pos has a value or not.

In your example given, getIt should return a fixed Position like (see flow.org/try):

function getIt(): Position {
  return {
    x:7,
    y: 8,
  }
}

Since you know 100% sure that pos is of type Position (because isOk can only be true if that's the case), you can explicitly typecast it to Position (which is a dirty way, I know) like (see flow.org/try):

isOk && setIt(((pos: any): Position));

Upvotes: 1

Related Questions