Home > OS >  Two-dimensional arrays Destructuring = Type error
Two-dimensional arrays Destructuring = Type error

Time:10-01

Could someone please explain to me TypeScript behavior here?

  • JavaScript

    const test1 = [
        ['a', 'b'],
        ['c', 'd'],
    ];
    
    const test2 = [
        ...[
            ['a', 'b'],
            ['c', 'd'],
        ],
    ];
    
    console.log(JSON.stringify(test1) === JSON.stringify(test2));
    

    Logs true as expected (arrays are identical).

  • TypeScript

    const test1: [string, string][] = [
        ['a', 'b'],
        ['c', 'd'],
    ];
    
    const test2: [string, string][] = [
        ...[
            ['a', 'b'],
            ['c', 'd'],
        ],
    ];
    

    This, however, leads to the following error on test2:

    Type 'string[][]' is not assignable to type '[string, string][]'.
      Type 'string[]' is not assignable to type '[string, string]'.
        Target requires 2 element(s) but source may have fewer.
    

Here is a reproducer on TypeScript Playground.

Am I doing something wrong here, or is there any way to get this to work without resorting to some ugly type casting?


UPDATE

Here is a more concrete example of what I'm trying to achieve:

const someValues = [1, 2, 3];

const test3: [string, string][] = [
    ...someValues.map(value => ['some string', 'another string']),
];

UPDATE #2

Following Алексей Мартинкевич advice, I can confirm that this works:

const someValues = [1, 2, 3];

const test3: (readonly [string, string])[] = [
    ...someValues.map(i => ['a', 'a'] as const),
];

Would there be a more readable/less complex solution though?
(thinking of my coworkers and 2-weeks-future-me wondering what I did there :D)

CodePudding user response:

This construction has type string[][], so it cannot be assigned to [string, string][].

...[
 ['a', 'b'],
 ['c', 'd'],
]

The following should work:

const test1: [string, string][] = [
    ['a', 'b'],
    ['c', 'd'],
];

const test2: [string, string][] = [
    ...test1,
];

You can use as const, but you need to keep everything readonly:

const test2: (readonly [string, string])[] = [
    ...[
        ['a', 'b'],
        ['c', 'd'],
    ] as const
]

Typescript assumes that array can be changed, so it uses more wide type by default.

CodePudding user response:

For your specific concrete case, you can indicate the return type on the arrow function given to map:

const someValues = [1, 2, 3];

const test3: [string, string][] = [
    ...someValues.map((value): [string, string] => ['some string', 'another string']),
];

You could also remove the type on the variable if you think it's explicit enough:

const test4 = [
    ...someValues.map((value): [string, string] => ['some string', 'another string']),
];
  • Related