Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flow allow concatenation with object.entries and string

I have a type like this:

type Cool = {
    [key: string]: number
}

Now, let's say I have an object with that type:

let my: Cool = {
    "asdf": 1,
    "jkl": 2
}

When I run Object.entries(my), I get [["asdf", 1], ["jkl", 2]]. This seems normal. However, I want to combine each key to form a string, like this:

let mystring = "";
Object.entries(my).forEach(entry => {
    mystring = entry[1] + mystring;
});

I would expect that mystring is equal to "jklasdf" and it is. However, I get a flow error on the mystring = ... line. The error states:

Cannot cast Object.entries(...)[0][1] to string because mixed [1] is incompatible with string

Any thoughts on how to fix this? Thanks!

like image 334
Ryan Z Avatar asked Jun 06 '19 21:06

Ryan Z


2 Answers

Object.entries is typed as:

static entries(object: $NotNullOrVoid): Array<[string, mixed]>

And when you try to use a value of a mixed type you must first figure out what the actual type is or you’ll end up with an error, so you can use Flow's type refinement :

Object.entries(my).forEach(entry => {
  if (typeof entry[1] === 'number') {
    mystring = entry[1] + mystring;
  }
});

You could also just cast entry[1]:

Object.entries(my).forEach(entry => {
  mystring = Number(entry[1]) + mystring;
});

or add type to entry like this entry: [string, any] but note that using any is completely unsafe, and should be avoided whenever possible.

DEMO

like image 191
Fraction Avatar answered Sep 23 '22 02:09

Fraction


Your problem is with the algorithm, not the types.

First of all, if you want mystring to equal "jklasdf", then you need to access the first index [0] like this entry[0], because the first element in the array is the key of object, if that's what you're looking for.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries

The Object.entries() method returns an array of a given object's own enumerable string-keyed property [key, value] pairs...

So your code -regardless of the types- should be:

let my = {
    "asdf": 1,
    "jkl": 2
}

let mystring = "";
Object.entries(my).forEach(entry => {
    mystring = entry[0] + mystring; // access the 0th element
});

console.log(mystring);
// jklasdf

So, now your flow types have no problem at all. https://flow.org/try/#0C4TwDgpgBAwg9nANlAvFA3gKCjqBtAawhAC4oBnYAJwEsA7AcwF0y6BXAWwCMIrMBfTJkQRgUDqVgJkaLLigAiAIbkAJgDMFZAIwAabLgUArAoi1QATAKEixEyrUapFCgNyYA8lyMQAxsAA6CDpqGghyAAoJAEoA9TgqAFElXwALCODqEFQAPgwDHHtQpzRMqhA8AAYmKABqcRAHegZ3fmjXIA

But, if I would recommend a more readable code to achieve the same result:

let my = {
    "asdf": 1,
    "jkl": 2
}

let mystring = "";
   
for (const [key, value] of Object.entries(my)) {
    mystring = [key, mystring].join('')
}

console.log(mystring);
// jklasdf

Or using Array.prototype.reduce:

let my = {
    "asdf": 1,
    "jkl": 2
}

const mystring = Object.entries(my)
                    .reduce((result, [key, value]) => {
                        return result = [key, result].join('');
                    }, "");

console.log(mystring);
// jklasdf
like image 36
Bahaà Addin Avatar answered Sep 27 '22 02:09

Bahaà Addin