```ts

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

  nodes.forEach(node => {
    inDegree.set(node, 0);
    graph.set(node, new Set());
  });

  edges.forEach(([from, to]) => {
    if (!graph.has(from)) {
      graph.set(from, new Set());
    }
    if (graph.has(to)) {
      throw Error(`Edge '${to}' references already existing node.`);
    }
    graph.get(from)!.add(to);
    inDegree.set(to, (inDegree.get(to)! || 0) + 1);
  });

  const order: string[] = [];
  while (nodes.length > 0) {
    const freeNodes = nodes.filter(node => inDegree.get(node) === 0);

    if (freeNodes.length === 0) {
      throw Error('Detected a cycle.');
    }

    const orderedNode = Array.from(freeNodes).sort((a, b) => nodes.indexOf(a) - nodes.indexOf(b))[0];

    order.push(orderedNode);
    graph.get(orderedNode)!.forEach(nextNode => inDegree.set(nextNode, (inDegree.get(nextNode)! || 0) - 1));
    nodes.splice(nodes.indexOf(orderedNode), 1);
  }

  return order;
}
```