Since you didn't annotate the type of headersWithIndex, the compiler inferred its type for you, based on heuristic rules about what people tend to do with arrays:
const headersWithIndex =
headers.map(header => [header, Number(headers.indexOf(header))]);
// const headersWithIndex: (string | number)[][]
That type, (string | number)[][] means "an array of arrays of string or number elements". That's not an incorrect description of headersWithIndex, and in other circumstances it would be a reasonable guess about what kinds of things you're likely to do with it:
headersWithIndex.push([1, "two", 3, "four"]); // okay
Unfortunately, that type is not specific enough to be accepted by the Map constructor, which expects an iterable whose elements are explicitly a 2-tuple of a key followed by a value. And so the construct call fails, because the compiler has forgotten anything about the particular ordering and length of the arrays inside the headersWithIndex elements.
The most straightforward way to fix this is to use a const assertion when you are creating the array literal containing the key and value:
const headersWithIndex =
headers.map(header => [header, Number(headers.indexOf(header))] as const);
// const headersWithIndex: (readonly [string, number])[]
return new Map(headersWithIndex); //okay
That as const gives the compiler a hint that you'd like it to infer something like the most specific type it can; it's almost like saying "I'm not going to change the contents of this thing, so please pay attention to exactly where everything is". And you'll see that now headersWithIndex is inferred as type (readonly [string, number])[]; that is, an array of readonly tuples consisting of one string followed by one number.
And now the Map constructor is happy, since it knows for sure that each element of headersWithIndex is a pair of a string key and a number value, resulting in a Map<string, number>.
Playground link to code