Ayon
Ayon

Reputation: 11

Typescript convert plain string to Map

I have this string (called stats):

active_total: 1087
cumulative: 1
trace_total: 10

which is not even in JSON format.

This is the solution that I am trying:

let keyValuePairs = stats
  .split(/\s*\n\s*/)                     //split with optional spaces around the comma
  .map(chunk => chunk.split(": "));      //split key=value
  
const map = new Map(keyValuePairs);

console.log(map.get("sessions_active_total"));
console.log(map.get("cumulative"));

But it is throwing compilation error at this line:

const map = new Map(keyValuePairs);

Error message:

error TS2769: No overload matches this call.
  Overload 1 of 3, '(iterable: Iterable<readonly [unknown, unknown]>): Map<unknown, unknown>', gave the following error.
    Argument of type 'string[][]' is not assignable to parameter of type 'Iterable<readonly [unknown, unknown]>'.
      The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
        Type 'IteratorResult<string[], any>' is not assignable to type 'IteratorResult<readonly [unknown, unknown], any>'.
          Type 'IteratorYieldResult<string[]>' is not assignable to type 'IteratorResult<readonly [unknown, unknown], any>'.
            Type 'IteratorYieldResult<string[]>' is not assignable to type 'IteratorYieldResult<readonly [unknown, unknown]>'.
              Type 'string[]' is not assignable to type 'readonly [unknown, unknown]'.
                Target requires 2 element(s) but source may have fewer.
  Overload 2 of 3, '(entries?: readonly (readonly [unknown, unknown])[]): Map<unknown, unknown>', gave the following error.
    Argument of type 'string[][]' is not assignable to parameter of type 'readonly (readonly [unknown, unknown])[]'.
      Type 'string[]' is not assignable to type 'readonly [unknown, unknown]'.

58         const map = new Map(keyValuePairs);

Upvotes: 1

Views: 641

Answers (1)

aleksxor
aleksxor

Reputation: 8340

Typescript is unable to infer the exact result of the chunk.split(": "). Even to be able to remotely guess it typescript should know the runtime value of the stats variable.

If you're looking for type safe solution I'd assume to use custom type predicate:

const isTupleOf2 = (chunk: string[]): chunk is [string, string] => chunk.length === 2

let keyValuePairs = stats
  .split(/\s*\n\s*/)
  .map((chunk: string) => chunk.split(": "))
  .filter(isTupleOf2)      
  
const map = new Map(keyValuePairs);

playground link

Or if you're absolutely sure the result will always be the one you expect you may use type assertion:

let keyValuePairs = stats
  .split(/\s*\n\s*/)
  .map((chunk: string) => chunk.split(": ") as [string, string])

const map = new Map(keyValuePairs);

playground link

Upvotes: 2

Related Questions