I've written a custom hook to rotate a 2d array that returns a state, matrix: string[][], and a function to rotate that matrix, rotateMatrix: () => void. When used in a component, TypeScript wants to refer to both 'matrix' and 'rotateMatrix' as a union type of both string[][] and ()=> void.
Unfortunately, this means that I cannot access the indices of 'matrix' because TypeScript can't be sure it is indeed a string[][], and I can't call 'rotateMatrix' because TypeScript can't be sure it is indeed a function.
How do I inform TypeScript that the state variable and function returned by a custom hook are their own definite types?
Snippet of my code:
type Matrix = (string | undefined) [][];
const testBoard: Matrix = [
['y', 'yx', 'y', 'yx', 'y', 'y', 'r', 'r'],
['y', 'y', 'y', 'y', 'y', 'y', 'r', 'rx'],
['o', 'o', 'o', 'o', 'y', 'yx', 'yx', 'y'],
['o', 'ox', 'ox', 'o', 'y', 'y', 'y', 'y'],
['g', 'gx', 'b', 'b', 'b', 'b', 't', 't'],
['gx', 'g', 'b', 'b', 'b', 'bx', 'tx', 't'],
['t', 't', 'b', 'bx', 'b', 'b', 't', 't'],
['tx', 't', 'b', 'b', 'bx', 'b', 't', 'tx']
];
function Board() {
const [board, rotateBoard] = useRotation(testBoard);
const [tiles, setTiles] = useState<TileProps[] | null>(null);
useEffect(() => {
const tileArr: TileProps[] = [];
for (let y=0; y < board[0].length; y = 2) {
for (let x=0; x< board.length; x = 2) {
const tile: TileProps = {
squares: [board[y][x], board[y][x 1], board[y 1][x 1], board[y 1][x]].join('_'),
row: y,
column: x,
gridRow: gridNumbers[y],
gridColumn: gridNumbers[x]
};
tileArr.push(tile);
}
}
setTiles(tileArr);
}, [board])
return (
<>
{ tiles
? <BoardFoundation onClick={rotateBoard}>
{tiles.map((tile: TileProps, index: number) => {
return <Tile key={index} squares={tile['squares']} row={tile.row} column={tile.column} gridRow={tile.gridRow} gridColumn={tile.gridColumn} />
})}
</BoardFoundation>
: null
}
</>
)
}
function useRotation( matrixNeedingRotation : Matrix ): ((Matrix | (() => void))[]) {
const [matrix, setMatrix] = useState<Matrix>(matrixNeedingRotation);
function rotateMatrix(): void {
const newMatrix = zip(...matrix);
setMatrix(newMatrix);
}
return [matrix, rotateMatrix];
}
Thank you very much for your help.
CodePudding user response:
Use a tuple as the return type of the function. It's going to be like the following:
function useRotation( matrixNeedingRotation : Matrix ): [Matrix, (() => void)] {
const [matrix, setMatrix] = useState<Matrix>(matrixNeedingRotation);
function rotateMatrix(): void {
const newMatrix = zip(...matrix);
setMatrix(newMatrix);
}
return [matrix, rotateMatrix];
}