Map and FlatMap throwing error “Property ‘map’ does not exist on type ‘unknown’ in Typescript

I have data object which is derived as below. It can have any number of Array object each representing count of ErrorType.

I am using Angular9 and writing the below code in TypeScript.

    const apiResponse = await this.service.geterrors();
    const data = apiResponse ['data'];

data = 
{
  "1": [
    {
      "ErrorType": "Error-1A",
      "Error": "Wrong Password for 1A"
    },
    {
      "ErrorType": "Error-1B",
      "Error": "Host not matching"
    }
  ],
  "2": [
    {
      "ErrorType": "Error-2A",
      "Error": "Wrong User for 1A"
    },
    {
      "ErrorType": "Error-2B",
      "Error": "connectivity issue"
    }
  ],
  "3": [
    {
      "ErrorType": "Error-3A",
      "Error": "Wrong version"
    }
  ],
  "16": [
    {
      "ErrorType": "Error-4A",
      "Error": "Unknown"
    }
  ]
  ...
  ... 
}

I want to capture all the count values and push them in an array counts in descending order.

counts = [16, 3, 2, 2, 1, 1];

I want to capture the corresponding ErrorType and push them in an array errorTypes.

errorTypes = ['Error-4A', 'Error-3A', 'Error-2B', 'Error-2A', 'Error-1B', 'Error-1A'];

I have written the following code so far but it is throwing errors:

const errs = Object.entries(data).map(([k, v]) => 
    [v.map(() => +k), v.map(e => e.ErrorType).reverse()]
  )
  .sort((a, b) => b[0][0] - a[0][0])
;
const [counts, errorTypes] = errs[0]
  .map((_, i) => errs.flatMap((_, j) => errs[j][i]))
;

console.log(counts, errorTypes);

The above code is throwing 2 errors:

  • TS2339: Property 'map' does not exist on type 'unknown'.

    TS2339: Property 'flatMap' does not exist on type 'any[][]'.

Answer

Your code is throwing errors because typescript isn’t sure if it has an array of numbers or an array of strings and it can’t map on that union.

This is more verbose than what you wrote, but I can’t wrap my head around what your code is actually doing so I just rewrote it. It turns out I didn’t need any advanced typescript stuff with this approach, though I did define types for our data structures.

interface TypedError {
    ErrorType: string;
    Error: string;
}

const data: Record<number, TypedError[]> = 
{...}

I put the errors into a record keyed by ErrorType which contains the ErrorType, count, and number of the group. Then I sort this by comparing the count properties of the elements.

interface ErrorCount {
    count: number;
    ErrorType: string;
    group: number;
}

const keyedCounts: Record<string, ErrorCount> = {};

Object.entries(data).forEach(
    ([num, arr]) => arr.forEach(
        ({ErrorType}) => keyedCounts[ErrorType] = {
            count: ( keyedCounts[ErrorType]?.count || 0 ) + 1,
            group: parseInt(num),
            ErrorType,
        }
    )
);

const sorted = Object.values(keyedCounts);
sorted.sort((a, b) => b.count - a.count)

From there, you can extract your arrays

const counts = sorted.map( o => o.count );
const names = sorted.map( o => o.ErrorType );

Typescript Playground Link

Leave a Reply

Your email address will not be published. Required fields are marked *