I am trying to figure out why a refinement is thrown out when using a ternary operator but not with an if else block. See the following code snippet.
handleError Fn
These aren't equivalent.
In the first function, your default case is to throw an Error. But in the second function, your default case is to set error === res.message || res.statusText.
What flow is saying here is, "hey, it's possible that res.message and res.statusText is undefined. If that's the case, then there's a conflict with error: string." To mimic the logic in the if-block example, you'd have to add error handling. Here is a working example.
function handleError(url: string, res: ResponseType): void {
let error: string;
if (!res.message || !res.statusText) {
throw new Error();
}
const error: string = res.status === 440 ?
'Session Timeout' :
res.message || res.statusText;
setTopState({error});
}
The documentation describes this under "Refinement Invalidations".
Related
I got the same problem with null statements (?) in Dart multiple times in different cases. I really hope somebody can help me.
Just added some lines of code & the error:
Error:
The property 'isEmpty' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!'). here
Here is one of my examples:
child: MaterialButton(
onPressed: () {
var currentState = this._formKey.currentState;
if (currentState == null) {
return;
}
if (_formKey.currentState.validate()) {
AuthService.instance.signIn(
email: emailTextEditingController.text,
password:
passwordTextEditingController.text);
if (AuthService.instance
.checkIfUserExists() ==
true) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => MainMenu()));
} else {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) =>
VerifyScreen()));
}
}
},
Got this error-message again:
The method 'validate' can't be unconditionally invoked because the receiver can be 'null'.Try making the call conditional (using '?.') or adding a null check to the target ('!').
After I edited the code with a ! to avoid the Null-Statement like:
singUpUser() {
if (formKey.currentState!.validate()) {
setState(() {
isLoading = true;
});
} else {
return null;
};
But now i just avoid the error in the code itself, after starting a emulator and testing it, next error appears:
Null check operator used on a null value
So thats not the right solution...
If you need more code, just message me.
Thank you!
Tom
In a nutshell: if Dart is certain that a variable at compile time can be null at runtime, it doesn't compile.. unless you explicitly check for null values, and/or promote the variable to be non-nullable with the ! operator (Dart is not always able to infer the non-nullability in certain situations, so it's our responsibility to promote them to non-nullable).
There's much more to know if you're curious ("why?", for starters), so I'd suggest to check the null safety documentation (quick read).
This being said, your code now changes:
(1) We must check if val is nullable, before accessing it. We can either use ! or .? to safely access it; note: the null check operator ! is the least safe null operator, it's likely that it will result in run time exceptions.
validator: (val) {
val==null || val?.isEmpty || val?.length<3
? "Enter Username 3+ characters"
: null
}
(2) I can't infer which method / variable can be null by myself
(3) It depends on what you're trying to do, but I guess that you're trying to implement the Firebase authentication process, in which your user can and should be null before authenticating. Therefore, your function should accept a nullable user value (User?). In there, we do the usual null check and we add a ! operator to promote its value in case user is not null. As aforementioned, Dart isn't always able to infer nullability of variables.
MyUser _userFromFirebaseUser(User? user) {
return user==null ? null : MyUser(userId: user!.uid);
}
Note how using a null-check ! here is perfectly safe, only because you just checked its nullability in the same line (nonetheless, keep a wise-eye when you refactor this).
EDIT. (4)
I can't infer where exactly your exception is fired, but since you want to validate your form, then here's my code from a project of mine:
// inside "saveForm()"...
var currentState = this._formKey.currentState;
if (currentState == null)
return; // this just means something went wrong
if (!currentState.validate()) return; // todo if invalid, handle this, maybe show a snackbar and stuff...
Note how the variable currentState is now promoted to be non-nullable WITHOUT using the null check operator !, which is just good practice (avoid using ! whenever possible, PREFER using null-aware operators, such as ?. or ??, or ?=)
Being empty is not the same as being null. So before you can check an object is empty, you need to check against null first.
if (obj != null && !obj.isEmpty) {}
I'm having som issues with updating Firebase from VueFire. I m trying to use the following method, but it yells at me if I leave any field blank (which is supposed to happen often in setup) Any idea why this gets mad if .update with a blank field?
Error: Uncaught Error: Firebase.update failed: First argument contains undefined in property 'businesses.somebusiness.video'
updatePost(post) {
postsRef.child(post['.key']).update({
name: post.name,
video: post.video,
story: post.story,
cover: post.cover,
card: post.card
})
},
At one point I had the above re-written like so:
updatePost: function (post) {
const businesschildKey = post['.key'];
delete post['.key'];
/* Set the updated post value */
this.$firebaseRefs.posts.child(businesschildKey).set(post)
},
It worked amazingly but deleting the key seemed to cause weird ordering issues in Vue. I would prefer to stick with the top method if I can find a way to not have it trow an error if one is left blank.
According to this post,
When you pass an object to Firebase, the values of the properties can
be a value or null (in which case the property will be removed). They
can not be undefined, which is what you're passing in according to the
error.
Your error message suggests that post.video's value is undefined. You can use logical-or to provide a fallback value like so:
video: post.video || null,
That means whenever post.video has a false-y value, the expression will evaluate to null. That could catch empty string or numeric 0, though. To be more precisely correct, you should use
video: typeof post.video === 'undefined' ? null : post.video,
If you need to do this check for many values, you can write a function for it:
function nullIfUndefined(value) {
return typeof value === 'undefined' ? null : value;
}
then your expression would just be
video: nullIfUndefined(post.video),
I'm wondering how to avoid these numerous null checks or at least understand what the point is because it seems counter-productive.
Flowtype is giving me an error for this if I omit the null check:
var myEl = new MyElement()
if (document.body != null) { // error on next line if omitted
document.body.appendChild(myEl)
}
I have to do that null check for the document body in every single callback too, because who knows, maybe the body is null here right?!
I think this is total overkill. Not only that, but what's the point of such a simple nullcheck? It will just silently skip over a vital part of the program and exhibit undefined behavior somewhere else and make debugging the app that much harder.
I'd really prefer just having a null exception at this point if an error ever happens here, because to be really sure this tiny 2-line code segment that I'd write in javascript would have to be like this in flowtype:
var myEl = new MyElement()
if (document.body != null) {
document.body.appendChild(myEl)
} else {
console.error("null error")
}
So 4 additional code lines and some nesting just to trace something I'd get for free if I just let the app run into an error. And I need those 4 lines on every single querySelector. On every single document.body. On every single getElementByTagName. This alone probably increases my entire codebase by 10%.
What's the point of enforcing this so strictly?
In other languages I'd also be able to try-catch around these hotspots gradually as needed, flow doesn't let me do that either. It shows errors whether I add a try-catch or not.
By using a type checker, you are opting into the rules that it enforces. Accessing a property on a nullable type is one of those restrictions. So if you want to have exceptions for null values, you need to explicitly throw to prove to Flow that it is what you want. You could for instance make a module like
if (!document.body) throw new Error("Unexpectedly missing <body>.");
export const body: HTMLElement = document.body;
export function querySelector(el: HTMLElement, selector: string): HTMLElement {
const result = el.querySelector(selector);
if (!result) throw new Error(`Failed to match: ${selector}`);
return result;
}
By throwing, these functions explicitly say "I will return an element" in all cases, and in null cases, they will throw exceptions.
Then in your normal code, you are guaranteed you can use those
import {body, querySelector} from "./utils";
body.appendChild(document.createElement('div'));
querySelector(body, 'div').setAttribute('thing', 'value');
and it will typecheck property.
When I know for sure that my variable won't be null and Flow doesn't, I use an unwrap() function:
export default function unwrap<T>(value: T): $NonMaybeType<T> {
if (value !== null && value !== undefined) return value
throw new Error('Unwrapping not possible because the variable is null or undefined!')
}
In the following example, since I'm using matching over type of Message using the switch statement, I would like flow to recognise my incorrect case of 'ENUM_TYPO'. It currently doesn't.
type Message = 'BROADCAST_MESSAGE' | 'PRIVATE_MESSAGE';
const message: Message = 'BROADCAST_MESSAGE';
switch (message) {
case 'ENUM_TYPO':
// Do Broadcast
break;
default:
break;
}
As of v0.32.0, Flow does not complain about unreachable code, unless it's something like
// #flow
function foo() {
throw new Error();
return 123; // This will error
}.
However, consider the following code
// #flow
function foo(x: string): Object {
if (x === 123) {
return x;
}
return {};
}
Will currently will not error on this code. Flow does in fact notice that x === 123 will never be true. Inside the if block, Flow will refine the type of x to the empty type, since it doesn't believe that this code will ever be reached. That is why it doesn't complain about the return x statement.
One of the members of the Flow team is almost done with adding reachability analysis to Flow. Once this improvement lands (I'm guessing v0.34.0?), Flow will complain when it sees a conditional that it thinks will always fail. This will help you with your example, since switch statement cases are basically strict equality checks.
I'm trying to perform a custom sort using a comparator function from within a template helper in Meteor.
Here is my template helper:
Template.move_list.helpers({
assets() {
return Assets.find({}, { sort: sortFunction });
}
});
And here is the comparator function:
const sortFunction = function (doc1, doc2) {
const barcodes = Session.get('barcodesArray');
if (barcodes.indexOf(doc1.barcode) === -1 || barcodes.indexOf(doc2.barcode) === -1) {
return 0;
}
let last = null;
_.each(barcodes, function (barcode) {
if (barcode === doc1.barcode) last = doc1.barcode;
if (barcode === doc2.barcode) last = doc2.barcode;
});
return last === doc1.barcode ? 1 : -1;
}
Error
When the page loads, the following error is returned:
Exception in template helper: Error: Match error: Failed Match.OneOf, Match.Maybe or Match.Optional validation
I put a breakpoint in chrome into the sortFunction, however the function was never entered and the breakpoint never reached.
Of course, the error is not throw when I remove sort.
References
This feature is not very well documented, however here is the relevant part of the docs:
For local collections you can pass a comparator function which receives two document objects, and returns -1 if the first document comes first in order, 1 if the second document comes first, or 0 if neither document comes before the other. This is a Minimongo extension to MongoDB.
And the commit by mitar adding the functionality, with example code from the test:
var sortFunction = function (doc1, doc2) {
return doc2.a - doc1.a;
};
c.find({}, {sort: sortFunction})
Can anyone make sense of this error?
Edit:
This issue should be resolved in Meteor >= v1.3.3.1.
Local collections (i.e, client-side and in-memory server-side collections) will allow to pass a function as the sort clause.
The error comes from the mongo package, where the spec does not allow sort to be a function.
#mitar changed LocalCollection in the minimongo package. LocalCollection is part of the Mongo.Collection object on the client (its _collection attribute), but queries are still checked according to the original mongo spec. I believe this to be a bug, as the spec was not updated to reflect the change.
To overcome this (in the meantime), either have the function accept a sub-field, such that the sort value is an object:
var sortFunction = function (x, y) {
return x - y;
};
c.find({}, {sort: {a: sortFunction}});
or use the c._collection.find() instead, which will work (as far as I can tell), except it will not apply any transformations defined for the collection.
var sortFunction = function (doc1, doc2) {
return doc2.a - doc1.a;
};
c._collection.find({}, {sort: sortFunction});