If default parameter can also have undefined value, flow complains with the error (see output below), but only if the parameter defined with ? optional parameter. In case `| void' is used - no issues.
If this is a bug, please try reproducing using https://flow.org/try/.
Yes, can be reproduces
/* @flow */
type Conf = {
id?: number,
};
const conf: Conf = {
id: -1,
}
const something = (id?: number = 5): number | void => {
return id;
}
const something2 = (id?: number = undefined): number | void => {
return id;
}
const something3 = (id?: number = conf.id): number | void => {
return id;
}
const something4 = (id: number | void = conf.id): number | void => {
return id;
}
something();
something2();
something3();
something4();
As a result flow complains to something2 and something3
14: const something2 = (id?: number = undefined): number | void => {
^ undefined [1] is incompatible with number [2].
References:
[LIB] ..//static/v0.86.0/flowlib/core.js:13: declare var undefined: void;
^ [1]
14: const something2 = (id?: number = undefined): number | void => {
^ [2]
18: const something3 = (id?: number = conf.id): number | void => {
^ undefined [1] is incompatible with number [2].
References:
4: id?: number,
^ [1]
18: const something3 = (id?: number = conf.id): number | void => {
^ [2]
param?: type is different from param: ?type. You may have top use param?: ?type if that is what you mean.
Myself, I added these two types:
/**
* This is a shortcut type so that instead of having to write the lengthy `void | T` one can
* simply write `Void<T>`. This is better than writing `?T` because that would include `null`.
* @typedef {undefined|*} Void
*/
export type Void<T> = void | T;
/**
* This is a shortcut type so that instead of having to write the lengthy `null | T` one can
* simply write `Null<T>`. This is better than writing `?T` because that would include
* `undefined`.
* @typedef {null|*} Null
*/
export type Null<T> = null | T;
I did that because I think Flow treating null and undefined the same really sucks. No would wold write, for example, param?: Void<type> when I mean an optional parameter that can be missing, or even when present can be receive undefined, which is possible when a function passes an optional parameter through (always present in the actual function call, but can be undefined if the calling function itself did not receive anything). This also gets rid of a lot of unnecessary null checks when I really only mean undefined. I think it expresses what is actually intended much better.
In any case, the one thing to keep in mind is the two very different meanings of the "?" depending on where it is, and that declaring a parameter optional (first position= is not the same as declaring it as possibly undefined or null (second position). One syntax is for function parameters only, the other one is the same for any type anywhere, to annotate it as including "undefined" and "null" as values in addition to the actual type values. Which is something I completely avoid and don't use any more, there is no more ?type anywhere in my code, replaced with the above wrappers. I think ?type syntax is "evil" and should not exist in the first place because it mixes undefined and null.
PS: JSDoc-ing all my Flow types helps with inline help in the IDE.
Hi @lll000111, thanks for your reply. Indeed null and undefined can be confusing, and it really nice idea to define export type Void<T> = void | T; or type Null.
But in the described case there is no null values at all, I do work with undefined only. This has some benefits over null, like default value, etc. Moreover flow produces error undefined [1] is incompatible with number [2], but number value is optional (id?: number which means it is a number or undefined).
Or maybe it should be better error reporting from flow? Like, for example, a message default parameter cannot have type undefined.
@rumax
But in the described case there is no null values at all,
I addressed TWO things at once. I covered this too... actually, rereading your reply, isn't that exactly my point? That, and that "?:" syntax for optional parameters is something completely different from the general syntax for types that may also be undefined and/or null.
Moreover flow produces error undefined [1] is incompatible with number [2], but number value is optional (id?: number which means it is a number or undefined).
So... what is the question? You already say it. I don't understand the "but" connecting the two parts of the sentence, the first follows from the second.
Or maybe it should be better error reporting from flow? Like, for example, a message default parameter cannot have type undefined.
The type of a parameter is different from declaring a parameter optional, for Flow. That's what I said. On the JS layer below Flow you end you with undefined in either case, but you are on the Flow layer. That is why you have TWO syntaxes: one for optional parameters, one telling Flow a type includes null and/or undefined.
If it is optional _and_ can also be null or undefined (if it is given and not a missing parameter) you need both syntaxes, just declaring it an optional parameter does not cover the second one even though on the JS level the result is "undefined" in both cases (but "?type" syntax also includes null, the optional param. syntax only includes undefined).
That is what I explained in my reply: Do not mix the two! Do not use ?type syntax — at all, and you won't have that confusion. Use param?: syntax for optional types, that's only results in undefined on the JS layer, and if a parameter, optional or not(!), can also be undefined (or null) regularly make that explicit _in addition_, possibly using my wrapper types to be more clear than the abysmal ?type syntax.
Anyway, look at this solution, just what I talked about above: Optional parameter is _different_ from declaring the type! _(I made changes to the parameter type declaration in lines 14 and 18)_
You declared the type number WITHOUT undefined. Declaring it optional has nothing to do with declaring the type! If you provide a value it must be of the given type! If you want to allow undefined as actual value (independent of missing, optional, parameters!), you must do so explicitly.
So, use
param?: void | number
instead of
param?: number
because you are assigning values, and those have to match the given type.
@lll000111, Thank you for your extended reply, but I didn't understand, do you confirm that it's a flow bug and it need to be fixed or you suggested to use workaround? Because in the bug description I've included a case (something4) which works. And the issue is const something3 = (id?: number = conf.id) which is correct according to flow documentation.
The following example without flow type:
var config1 = { id: -1 };
var config2 = { };
var someFunction1 = (id = config1.id) => {
return id;
}
var someFunction2 = (id = config2.id) => {
return id;
}
console.log(someFunction1(1));
// 1
console.log(someFunction1());
// -1
console.log(someFunction2(1));
// 1
console.log(someFunction2());
// undefined
works without any issues. Moreover I cannot find anything in JavaScript standard that says that the default value cannot have undefined value. And this situation can happen in big projects.
It is not a bug. Optional parameters != parameters that can also be undefined.
Your case 4 DOES declare undefined as possible value of the parameter, so of course it works. Did you look at my Flow-Try link?
The following example without flow type:
Well,why wouldn't it?
Please read again what I wrote about optional parameters having nothing to do with the type. YOU mix and confuse the two (of course, that's because Flow makes it confusing, I hate what they did, like using the "?" for two very different things, the ?type should not even exist).
You also get confused about "JS level undefined" and "Flow type level undefined". In the former an optional parameter and a parameter with value undefined are the same, on the Flow level they are not!
Optional parameters != parameters that can also be undefined.
Optional parameter is defined with a variable. Variable can have any value according to type. So it's a bug. Or, please, refer to JavaScript standard that doesn't allow this.
JavaScript standard
THIS IS FLOW, it's about TYPES!!!
Just _read_ what I wrote. Ridiculous!
Over and _out_ — I gave you far more than you need to understand and solve your problem, including an example (did you even look at it?!).
If your type definition does not include undefined, so you get an error when you set it to undefined. Flow is correct! That the parameter can be left out and then on the JS level also is undefined has nothing to do with it, read what I wrote about it! From a TYPE(!!!) point of view a missing parameter is something entirely different than a parameter (deliberately, actually, by code) set to undefined. Yes on the JS level it's the same result, but you are using a TYPE SYSTEM on top of JS. It checks types.
PS: Please don't mention me any more (using @lll000111), I'll unsubscribe from this issue, since I already said everything there is to reasonably say.