Awesome Reviewers

When extending APIs with new capabilities, carefully consider how changes to return values affect consumers. Avoid creating polymorphic return types based on input options as this reduces predictability and makes it difficult to programmatically detect supported features.

Instead, follow these patterns:

  1. For APIs already returning objects:
    • Extend the existing object with new capabilities (e.g., adding Symbol.dispose)
    • Maintain backward compatibility by preserving all existing properties
  2. For APIs returning primitives or immutable types:
    • Create a new, distinctly named API variant (e.g., mkdtempmkdtempDisposable)
    • Return an object that includes both the original value and the new capability
    • Clearly document the relationship between the original and new APIs
// AVOID: Polymorphic returns based on options
function createTempDir(prefix, { disposable = false } = {}) {
  const path = makeTempDir(prefix);
  return disposable ? 
    { path, [Symbol.dispose]: () => removeTempDir(path) } : 
    path;
}

// BETTER: Separate, clearly named APIs
function createTempDir(prefix) {
  return makeTempDir(prefix);
}

function createDisposableTempDir(prefix) {
  const path = makeTempDir(prefix);
  return {
    path,
    [Symbol.dispose]: () => removeTempDir(path)
  };
}

When introducing new return types: