```ts
/**
 * Merges overlapping or touching intervals and returns them sorted by start.
 * @param intervals - Array of [start, end] pairs with start <= end.
 * @returns New array of merged intervals sorted by start.
 */
export function mergeIntervals(intervals: [number, number][]): [number, number][] {
  if (!Array.isArray(intervals)) {
    throw new Error("Input must be an array");
  }

  // Validate input intervals
  for (let i = 0; i < intervals.length; i++) {
    const interval = intervals[i];
    if (!Array.isArray(interval) || interval.length !== 2) {
      throw new Error("Each interval must be a two-element array");
    }
    const [start, end] = interval as [number, number];
    if (typeof start !== "number" || typeof end !== "number") {
      throw new Error("Interval values must be numbers");
    }
    if (!Number.isFinite(start) || !Number.isFinite(end)) {
      throw new Error("Interval values must be finite numbers");
    }
    if (start > end) {
      throw new Error("Start of interval must be <= end");
    }
  }

  // Create a shallow copy to avoid mutating the input
  const sortedIntervals = [...intervals].sort((a, b) => a[0] - b[0]);

  if (sortedIntervals.length === 0) {
    return [];
  }

  const merged: [number, number][] = [];
  let currentInterval = sortedIntervals[0];

  for (let i = 1; i < sortedIntervals.length; i++) {
    const nextInterval = sortedIntervals[i];
    
    // Check if intervals overlap or touch
    if (currentInterval[1] >= nextInterval[0]) {
      // Merge by extending the end if necessary
      currentInterval = [currentInterval[0], Math.max(currentInterval[1], nextInterval[1])] as [number, number];
    } else {
      // No overlap, push current and move to next
      merged.push(currentInterval);
      currentInterval = nextInterval;
    }
  }

  merged.push(currentInterval);
  return merged;
}
```