typescript

Why can I initialize a Map with an iterable literal but not a variable of an iterable?


I can initialize a new Map() with a literal iterable (array of tuples) without a problem:

const tmp = new Map([
  [1, true],
  [2, false]
])

But if I try to initialize the Map with an iterable array:

const d = [
  [1, true],
  [2, false]
]
const tmp = new Map(d)

I receive error: (I'm not understanding the error)

TS2769: No overload matches this call. Overload  1  of  4 , (iterable?: Iterable<readonly [unknown, unknown]>): Map<unknown, unknown> , gave the following error. Argument of type  (number | boolean)[][]  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<(number | boolean)[], any>  is not assignable to type IteratorResult<readonly [unknown, unknown], any> Type IteratorYieldResult<(number | boolean)[]>  is not assignable to type IteratorResult<readonly [unknown, unknown], any> Type IteratorYieldResult<(number | boolean)[]>  is not assignable to type IteratorYieldResult<readonly [unknown, unknown]> Type  (number | boolean)[]  is not assignable to type  readonly [unknown, unknown]  Target requires  2  element(s) but source may have fewer.


Solution

  • MapConstructor requires readonly array of readonly tuples of size 2.

    interface MapConstructor {
        new(): Map<any, any>;
        new<K, V>(entries?: readonly (readonly [K, V])[] | null): Map<K, V>;
        readonly prototype: Map<any, any>;
    }
    

    If you assign an array to a temporary variable, it is inferred to be mutable array of arrays:

    const d = [
      [1, true],
      [2, false]
    ];
    // const d: (number | boolean)[][]
    

    You can use as const assertion to force it to be readonly tuple of readonly tuples:

    const d = [
      [1, true],
      [2, false]
    ] as const;
    // const d: readonly [readonly [1, true], readonly [2, false]]
    const tmp = new Map(d);