Make flow assume that a particular key does exist in a Map - flowtype

Due to the way you're iterating over something, you may know that a key always exists in a Map but flow may not know.
Currently, how I'm getting rid of it is to check if the result returned from get() is not undefined.
I don't want to add those spurious checks though, and instead I want to tell the typesystem that it can assume that that key exists. Telling this to the typesystem also conveys more information (this key definitely exists) about the program to a future reader than a spurious check (this key may or may not exist, and if doesn't exist then we're ignoring that case)
So I want to be able to do the following by preferably adding something on or before line 3 instead of an if check.
1. let score:Map<string, number> = new Map()
2. initialize(score); // some magic initilization of the map that flow doesn't understand
3. score.get("hello");

I wouldn't recommend doing this but you could extend the Map class to define your own class that defines get,
declare class MyMap<K, V> extends Map<K,V> {
get(key: 'hello'): V;
get(key: K): V | void;
}
so that (new myMap()).get('hello') has type V instead of V | void. For example,
const myMap: MyMap<string, number> = new MyMap();
const n: number = myMap.get('hello');
const o: number = myMap.get('not hello'); // error
const p: number | void = myMap.get('not hello');
Try Flow
You'll need to change your code so that initialize returns a MyMap instead of modifying the passed in Map. Note that although this will pass Flow, it may still break during running. As you can see in the example above, even though I have created a new MyMap(), I have not added the key 'hello' and so n isn't really a number.

Related

Firestore rule to only add/remove one item of array

To optimize usage, I have a Firestore collection with only one document, consisting in a single field, which is an array of strings.
This is what the data looks like in the collection. Just one document with one field, which is an array:
On the client side, the app is simply retrieving the entire status document, picking one at random, and then sending the entire array back minus the one it picked
var all = await metaRef.doc("status").get();
List tokens=all['all'];
var r=new Random();
int numar=r.nextInt(tokens.length);
var ales=tokens[numar];
tokens.removeAt(numar);
metaRef.doc("status").set({"all":tokens});
Then it tries to do some stuff with the string, which may fail or succeed. If it succeeds, then no more writing to the database, but if it fails it fetches that array again, adds the string back and pushes it:
var all = await metaRef.doc("status").get();
List tokens=all['all'];
List<String> toate=(tokens.map((element) => element as String).toList());
toate.add(ales.toString());
metaRef.doc("status").set({"all":toate});
You can use the methods associated with the Set object.
Here is an example to check that only 1 item was removed:
allow update: if checkremoveonlyoneitem()
function checkremoveonlyoneitem() {
let set = resource.data.array.toSet();
let setafter = request.resource.data.array.toSet();
return set.size() == setafter.size() + 1
&& set.intersection(setafter).size() == 1;
}
Then you can check that only one item was added. And you should also add additional checks in case the array does not exist on your doc.
If you are not sure about how the app performs the task i.e., successfully or not, then I guess it is nice idea to implement this logic in the client code. You can just make a simple conditional block which deletes the field from the document if the operation succeeds, either due to offline condition or any other issue. You can find the following sample from the following document regarding how to do it. Like this, with just one write you can delete the field which the user picks without updating the whole document.
city_ref = db.collection(u'cities').document(u'BJ')
city_ref.update({
u'capital': firestore.DELETE_FIELD
})snippets.py

What exactly does it mean when we say we cannot mutate the state object in Redux reducer?

Does it exactly mean treating it as "read-only"?
For example, if the state is:
{
arr: arrData,
obj: objData,
aMap: mapData,
aSet: setData
}
For any of the four that has no change to it, we can keep it as is, but let's say 3 level down obj, which is obj.b.c.d, and this d refers to an array, and we need to modify one entry in the array, then we need to make a copy of that array, modify the entry, and let the new state refer to it? But if d refers to a new array, then c needs to have a new d, so c needs to be a new object, and for the same reason, we need a new b, eventually, a new obj?
So it is
let objNew = {
...obj,
b: {
...obj.b,
c: {
...obj.b.c,
d: [...obj.b.c.d]
}
}
};
objNew.b.c.d[someIndex] = someNewValueOrObj;
And now objNew can be returned and the old state was not modified in any way (was reading it only).
So if prevState was the old state, and state is the new state, we just need to make sure right before we return the new state, for prevState, if we were to dump all the values out, it stayed the same as what was passed in, while the new state would dump out the values for our new state.
Redux uses shallow equality to check whether the state has changed to trigger a render in React. If the references to the new state and the previous are the same, i.e. === returns true, Redux considers nothing has changed and simply returns from the reducer.
You will have to produce a new state value that is referentially different to the old one no matter how deep down in your state a value has changed.
I would suggest you consider using a library like immer to help you with that in an efficient way.

Hashable tuple-like collections in TypeScript

I'm writing a (toy) hash-and-cache decorator in TypeScript and can't find a good means of creating a solid generic one.
The code I have so far is
function cache
(target: Object,
propertyKey: string,
// Likely we can do better than <any> here -- <Function<any>> maybe?
descriptor: TypedPropertyDescriptor<any>)
{
let cacheMap = new Map();
let wrappedFn = descriptor.value;
descriptor.value = function (...args: any[]) {
if (cacheMap.has(args)) {
console.log("Short-circuiting with result: " + cacheMap.get(args));
return cacheMap.get(args);
}
let result = wrappedFn.apply(this, args);
cacheMap.set(args, result);
console.log("cacheMap %o", cacheMap);
return result;
}
return descriptor;
}
Naturally this fails, since args is not a tuple but a list, which is mutable[1]. So each input, even if it's the same over and over, gets its own list/array in its own memory location with its own hash value, wherever that comes from.
I haven't found a Tuple type in TypeScript (or JS) yet -- is there one? Is there another workaround for this sort of problem?
Shouldn't this be an error? Map<T, U> should constrain T to implementing IHashable or something, right? That's the point of types -- to raise this issue before it takes a bunch of time out of your life.
Shouldn't this be an error? Map<T, U> should constrain T to implementing IHashable or something, right?
No. Object identity is a real and well-defined thing in JavaScript; TypeScript doesn't attempt to force you to pretend it doesn't exist.
If the ECMAScript committee thought it was appropriate to enforce non-object-identity-based keying in maps, they could have restricted Map keys, but they didn't.

need help understanding how to use dictionaries

I am a novice with regards to the swift 3 programming language though I am familiar basically with C++.
I am trying to learn to use dictionaries in Swift 3; which I believe are similar to hashes in C++. I have a dictionary with several key:value pairs in it.
I want to take a certain, single key (which I won't know in advance) and extract from that dictionary the corresponding value.
I know there will be a single key with that name, although the same value will be associated with keys of different names.
After extracting that value from the key:value pair of that dictionary then I want to store that single value in a variable as a string.
What type of code could do that?
I found some code that seems it might be helpful but I'm not sure and I'm not sure too how to use that code(how to write it actually) to make it perform as I wish.
extension Dictionary where Value: Equatable {
func someKeyFor(value: Value) -> Key? {
guard let index = indexOf({ $0.1 == value }) else {
return nil
}
return self[index].0
}
}
This is straight-forward dictionary access; no need to use extensions.
var myDictionary = [String:String]()
// At some point strings are put into the dictionary
// e.g. myDictionary["SomeKey"] = "SomeString"
// then you can say
if let someString = myDictionary[key] {
// You can now do something with someString
}
Keys and objects don't have to be strings, of course
I would suggest you read the Swift book from Apple in iBooks and try things out in in a Swift Playground in Xcode.

How do I type a function with input and output objects with the same keys but different value types?

Basically, I have a function that will transform an object into a different object, and it's like a dictionary, but I don't know how to type it.
var myFunctions = {
a: () => something1,
b: () => something2,
[...]
}
gets transformed into
var myObject = {
a: something1,
b: something2
[...]
}
With Flow 0.33+ you can use $ObjMap
type ExtractCodomain = <V>(v: () => V) => V;
declare function f<O>(o: O): $ObjMap<O, ExtractCodomain>;
I don't think you can do this with Flow. The closest you can get is probably this:
function<T>(obj: T): ([key: $Keys<T>]: boolean)
That function is typed to return an object with the same key as input object, but with boolean-only values (as an example, you can specify another type). Sorry to disappoint, but it's hard to type highly dynamic code with Flow in general.
Note that the $Keys feature is undocumented because it's not part of the public API, so its behavior is defined solely by its implementation (in other words, it can change anytime).
If you're interested in the details of Flow's type system, check out the typings that come with flow in its own /lib directory, for example https://github.com/facebook/flow/blob/master/lib/core.js – you'll see that some things like Object.assign are special-cased, so you might not be able to re-implement such things in your own code.
Also, check out http://sitr.us/2015/05/31/advanced-features-in-flow.html for other "dollar features" such as $Shape and $Diff – it's partially outdated, but can give some good pointers.
#Nikita gave you the best answer for now. That said, the use-case you talked about is being discussed in the issues on the FlowType repository. It may land soon.
As of right now, if you've got mixed type, I'll just fallback to any
function<T>(obj: T): ([key: $Keys<T>]: any)
This way, at least the key names are validated. I expect within a few more versions of Flow, this problem will get solved.

Resources