```typescript
function topologicalSort(nodes: readonly string[], edges: readonly (readonly [string, string])[]): string[] {
  const graph = new Map<string, Set<string>>();

  for (const [from, to] of edges) {
    if (!graph.has(from)) {
      graph.set(from, new Set());
    }
    if (!graph.has(to)) {
      graph.set(to, new Set());
    }

    graph.get(from)?.add(to);
  }

  const inDegree = new Map<string, number>();
  nodes.forEach(node => inDegree.set(node, 0));

  for (const [from] of edges) {
    inDegree.set(from, inDegree.get(from)! + 1);
  }

  const queue: string[] = [...nodes.filter(node => !inDegree.has(node))];

  const order: string[] = [];

  while (queue.length > 0) {
    const current = queue.shift()!;
    order.push(current);

    for (const next of graph.get(current)! || []) {
      inDegree.set(next, inDegree.get(next)! - 1);
      if (!inDegree.has(next) || inDegree.get(next)! === 0) {
        queue.push(next);
      }
    }
  }

  if (nodes.length !== order.length) {
    throw new Error('Cycle detected');
  }

  return order;
}
```