```ts
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[][] = [];
  for (let i = 0; i <= grid.length; i++) {
    prefixSumTable[i] = [0];
    for (let j = 0; j <= width; j++) {
      if (i === 0) {
        prefixSumTable[i][j] = j > 0 ? prefixSumTable[i][j - 1] + grid[0][j - 1] : 0;
      } else if (j === 0) {
        prefixSumTable[i][j] = i > 0 ? prefixSumTable[i - 1][j] + grid[i - 1][0] : 0;
      } else {
        prefixSumTable[i][j] =
          prefixSumTable[i - 1][j] +
          prefixSumTable[i][j - 1] -
          prefixSumTable[i - 1][j - 1] +
          grid[i - 1][j - 1];
      }
    }
  }

  const results: number[] = [];
  for (const [top, left, bottom, right] of queries) {
    if (
      !Array.isArray(query) ||
      query.length !== 4 ||
      !Number.isInteger(top) || !Number.isInteger(left) || !Number.isInteger(bottom) || !Number.isInteger(right)
    ) {
      throw new Error("queries must be lists of exactly four integers");
    }
    if (top >= bottom || left >= right) {
      throw new Error("query top and left must be strictly less than their respective bottoms and rights");
    }

    const total = prefixSumTable[bottom][right] -
                  prefixSumTable[top][right] -
                  prefixSumTable[bottom][left] +
                  prefixSumTable[top][left];

    results.push(total);
  }

  return results;
}
```