FIELD NOTE 025TypeScriptReviewed July 2026

Shuffle Array (Fisher-Yates Algorithm)

Fair and unbiased array shuffling using the Fisher-Yates (Knuth) shuffle algorithm

Copy the complete example or adapt its typed interface to your project. Comments are kept inside the snippet so the intent travels with the code.

pattern.ts
/**
 * Shuffle array using Fisher-Yates (Knuth) algorithm
 * @param arr Array to shuffle
 * @returns New shuffled array (original remains unchanged)
 */
function shuffleArray<T>(arr: T[]): T[] {
  const array = [...arr];
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
  return array;
}

// Usage Example
const numbers = [1, 2, 3, 4, 5];
const shuffled = shuffleArray(numbers);
console.log(shuffled); // Random order like [3, 1, 5, 2, 4]
console.log(numbers); // [1, 2, 3, 4, 5] (original unchanged)

Perfect for randomizing quiz questions, game mechanics, or any scenario requiring fair randomization

Implementation note

Review the input assumptions and browser or runtime support before adopting a utility unchanged. Small helpers are easiest to maintain when their contract stays narrow.

How it works

Fisher–Yates walks backward through a copied array and swaps each position with a randomly selected earlier position. With an unbiased random source, every permutation has equal probability and the input remains unchanged.

What to watch for

Math.random is unsuitable for security, gambling, or high-stakes fairness. Accidentally iterating in the wrong direction or selecting from the full array on every step introduces measurable bias.

Production use

Use this implementation for UI ordering, games without stakes, and test-data variety. Inject a seeded random source for reproducible tests, and use an audited cryptographic source when fairness or unpredictability is a requirement.

Before you ship

  • Confirm the input contract with tests that cover empty, invalid, boundary, and representative real-world values before sharing the helper across a codebase.
  • Keep the function focused on one responsibility and name any project-specific policy explicitly instead of hiding it inside a generic-looking utility.
  • Measure behavior in the browsers or runtime versions your product supports, especially when timing, storage, DOM state, locale, or network access is involved.
  • Document the return type, mutation behavior, failure mode, and performance characteristics beside the call site so future maintainers can evaluate changes safely.
  • Compare the example with current official platform documentation when it relies on a browser API, language feature, or runtime behavior that may change over time.
  • If the helper crosses a trust boundary, validate again on the server and avoid treating browser-side checks, TypeScript annotations, or formatted output as a security guarantee.
  • Add a small regression test whenever a real edge case is discovered; concrete examples preserve the reason behind a guard more reliably than a general comment.