```typescript
export function regionTotals(grid: number[][], queries: number[][]): number[] {
  if (!Array.isArray(grid) || grid.length === 0) {
    throw new Error("grid must be a non-empty list of rows");
  }
  const width = Array.isArray(grid[0]) ? grid[0].length : 0;
  if (width === 0) {
    throw new Error("rows must be non-empty lists");
  }
  for (const row of grid) {
    if (!Array.isArray(row) || row.length !== width) {
      throw new Error("rows must all share one length");
    }
    for (const cell of row) {
      if (!Number.isInteger(cell)) {
        throw new Error("cells must be integers");
      }
    }
  }

  const prefixSumTable: number[][] = Array.from({ length: grid.length + 1 }, () =>
    Array(width + 1).fill(0)
  );

  for (let row = 1; row <= grid.length; row++) {
    for (let col = 1; col <= width; col++) {
      prefixSumTable[row][col] =
        grid[row - 1][col - 1] +
        prefixSumTable[row - 1][col] +
        prefixSumTable[row][col - 1] -
        prefixSumTable[row - 1][col - 1];
    }
  }

  const calculateQueryTotal = (query: number[]): number => {
    const [top, left, bottom, right] = query;
    if (
      !Array.isArray(query) ||
      query.length !== 4 ||
      top >= bottom || left >= right
    ) {
      throw new Error("invalid or out-of-bounds query");
    }

    return (
      prefixSumTable[bottom][right] -
      prefixSumTable[top - 1][right] -
      prefixSumTable[bottom][left - 1] +
      prefixSumTable[top - 1][left - 1]
    );
  };

  const results: number[] = queries.map(calculateQueryTotal);
  return results;
}
```