```ts
export function regionTotals(grid: number[][], queries: number[][]): number[] {
  if (
    !Array.isArray(grid) ||
    grid.length === 0 || 
    grid.some(row => !Array.isArray(row) || row.length === 0)
  ) {
    throw new Error("grid must be a non-empty list of rows");
  }
  const width = grid[0].length;
  if (width === 0) {
    throw new Error("rows must be non-empty lists");
  }

  for (const row of grid) {
    if (!row.every(Number.isInteger)) {
      throw new Error("cells must be integers");
    }
    if (row.length !== width) {
      throw new Error("all rows must have the same length");
    }
  }

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

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

  return queries.map(([top, left, bottom, right]) => {
    if (
      !Array.isArray(query) ||
      query.length !== 4 ||
      !query.every(Number.isInteger)
    ) {
      throw new Error("queries must be lists of exactly four integers");
    }
    [top, left, bottom, right] = query.map(n => n - 1); // Convert to zero-based index
    if (
      top >= grid.length || 
      bottom <= top || 
      left >= width || 
      right <= left
    ) {
      throw new Error("queries must have valid bounds");
    }
    return prefixSumTable[bottom + 1][right + 1] -
           prefixSumTable[top][right + 1] -
           prefixSumTable[bottom + 1][left] +
           prefixSumTable[top][left];
  });
}
```