typescripttuples

How to use array.map with tuples in typescript?


Whenever I use array.map on a tuple, Typescript infers it as a generic array. For instance, here are some pieces of a simple 3x3 sudoku game:

const _ = ' ' // a "Blank"

type Blank = typeof _

type Cell = number | Blank

type Three = [Cell, Cell, Cell]

type Board = [Three, Three, Three]

const initialBoard: Board = [
    [_, 1, 3],
    [3, _, 1],
    [1, _, _],
]

// Adds a `2` to the first cell on the first row
function applyMove(board: Board): Board {
    // đŸ‘‡errors here
    const newBoard: Board =  board.map((row: Three, index: number) => {
        if (index === 0) return <Three> [2, 1, 3]
        return <Three> row
    })
    return newBoard
}

function applyMoveToRow(row: Three): Three {
    // return [2, 1, 3] // This works
    const newRow: Three = [
        2,
        ...row.slice(1, 3)
    ]
    return newRow
}

The TS error is:

Type '[Cell, Cell, Cell][]' is missing the following properties from type 
 '[[Cell, Cell, Cell], [Cell, Cell, Cell], [Cell, Cell, Cell]]': 0, 1, 2 .  

here it is in a TS Playground.

Is there any way to tell typescript that, when I'm mapping over a tuple, it's going to return a tuple of the same kind, instead of just an array? I've tried being very explicit, annotating all of my return values, etc, but it's not doing the trick.

There's a discussion on the Typescript github about this: https://github.com/Microsoft/TypeScript/issues/11312

But I haven't been able to get a solution out of it.


Solution

  • If you don't mind tweaking the way you assign initialBoard you can change your Board definition to this:

    interface Board  {
        [0]: Three,
        [1]: Three,
        [2]: Three,
        map(mapFunction: (row: Three, index: number, array: Board) => Three): Board;
    }
    

    This is how you have to change the way you assign a literal to a Board:

    const initialBoard: Board = <Board><any>[
        [_, 1, 3],
        [3, _, 1],
        [1, _, _],
    ]