JD.
JD.

Reputation: 2487

Flow - maybe types incompatible with seemingly valid default object parameters

Consider the code:

// @flow
type Params = {
  value: ?number,
}
function acceptsMaybeNumber({

  // Error:(6, 3) null or undefined [1] is incompatible with number [2].
  // value = 4 // <--- DOESN'T WORK

  // Error:(7, 3) null or undefined [1] is incompatible with number [2].
  // Error:(7, 11) null [1] is incompatible with number [2].
  // value = null // <--- DOESN'T WORK

  // Error:(15, 3) null or undefined [1] is incompatible with number [2].
  // Error:(16, 11) undefined [1] is incompatible with number [2].
  // value = undefined // <--- DOESN'T WORK

  value // <-- WORKS
}: Params) {
  console.log(value);
}

Since the value key in Params type accepts number, null, and undefined types, setting the default value of this key to either of those should be valid but instead throws the below errors.

Why does this happen?

Upvotes: 1

Views: 2103

Answers (2)

Dave Meehan
Dave Meehan

Reputation: 3201

As noted by @TLadd, it does appear to be a bug.

The problem is specifically with using null as a permitted type when object destructuring with a default value.

$FlowFixMe can be used to suppress the error, to avoid mangling your code, or you could create your own suppression e.g. $FlowDestructuringDefaultBug. NB: You need to put the $Flow suppression comment on the line immediately preceding the default assignment, so you need to break your parameters across multiple lines as you did in your original example.

Here are some alternatives which might fit your use case (Try):

// @flow
type MaybeParams = {
  value: ?number,
}
function acceptsMaybeNumber({
  // originalValue = 1  // FAIL
  // $FlowFixMe
  value = 1,            // PASS (but not in Try where $FlowFixMe is disabled)
}: MaybeParams) {
  console.log(value);
}

type OptionalParams = {
  value?: number,
}
function acceptsOptionalNumber({
  value = 1,                // PASS
}: OptionalParams) {
  console.log(value);
}

acceptsOptionalNumber({ })  // PASS


type UndefinedParams = {
  value: void | number,
}
function acceptsUndefinedNumber({
  value = 1,                // PASS
}: UndefinedParams) {
  console.log(value);
}

acceptsUndefinedNumber({ value: undefined })    // PASS

If you specifically want to handle null as a permitted, specified value, then you'll have to avoid the default value assignment in the destructuring.

Upvotes: 2

TLadd
TLadd

Reputation: 6884

It's a bug in flow. https://github.com/facebook/flow/issues/183#issuecomment-358607052. Easiest fix is probably to just not rely on the default destructuring value. So something like

type Params = {
  value?: ?number,
}
function acceptsMaybeNumber(params: Params) {
  const value = typeof params.value === 'number' ? params.value : 4
  console.log(value);
}

Upvotes: 2

Related Questions