```ts
export function turnCostRoute(grid: number[][], stepCost: number, turnCost: number): number {
  if (grid.length === 0 || grid.some(row => row.length !== grid[0].length)) {
    throw new Error("Invalid grid: empty or ragged");
  }
  if (!Number.isInteger(stepCost) || stepCost <= 0) {
    throw new Error("stepCost must be a positive integer");
  }
  if (!Number.isInteger(turnCost) || turnCost < 0) {
    throw new Error("turnCost must be a non-negative integer");
  }

  const numRows = grid.length;
  const numCols = grid[0].length;

  if (grid[0][0] === 1 || grid[numRows - 1][numCols - 1] === 1) {
    return -1;
  }
  if (numRows === 1 && numCols === 1) {
    return 0;
  }

  const directions = [
    { dr: -1, dc: 0 }, // up
    { dr: 1, dc: 0 },  // down
    { dr: 0, dc: -1 }, // left
    { dr: 0, dc: 1 }   // right
  ];

  const isValidCell = (r: number, c: number) => r >= 0 && r < numRows && c >= 0 && c < numCols && grid[r][c] === 0;

  interface State {
    row: number;
    col: number;
    dirIndex: number; // index into directions array
    cost: number;
  }

  const pq: State[] = [{ row: 0, col: 0, dirIndex: -1, cost: 0 }];
  const visited = new Set<string>();

  while (pq.length > 0) {
    pq.sort((a, b) => a.cost - b.cost);
    const { row, col, dirIndex, cost } = pq.shift()!;

    if (row === numRows - 1 && col === numCols - 1) {
      return cost;
    }

    const key = `${row},${col},${dirIndex}`;
    if (visited.has(key)) continue;
    visited.add(key);

    for (let i = 0; i < directions.length; i++) {
      const { dr, dc } = directions[i];
      const newRow = row + dr;
      const newCol = col + dc;

      if (!isValidCell(newRow, newCol)) continue;

      const newDirIndex = directions.findIndex(d => d.dr === dr && d.dc === dc);
      const turnCostToAdd = dirIndex === -1 ? 0 : (newDirIndex !== dirIndex ? turnCost : 0);

      pq.push({
        row: newRow,
        col: newCol,
        dirIndex: newDirIndex,
        cost: cost + stepCost + turnCostToAdd
      });
    }
  }

  return -1;
}
```