R04BREAKINGfunction

Parameter Type Narrowed

Flags when a parameter's type becomes more restrictive. Callers passing the previously valid, broader type will fail type checking.


Applies to

TypeScriptPythonGoJavaRust

Why it matters

Narrowing a parameter type invalidates all callers that relied on the broader type. For example, changing string | number to string breaks every caller passing a number.

Example

Before (accepts string | number | Buffer)
// parser.ts
export function parseInput(
  input: string | number | Buffer
): ParsedData { ... }
After (only string)
// parser.ts (BREAKING — type narrowed)
export function parseInput(
  input: string  // Buffer and number no longer accepted
): ParsedData { ... }

What you see in the terminal

$ npx dg check

  [BREAKING] parseInput (signature_change)
  src/parser.ts:3
  Parameter 'input' type was narrowed from 'string | number | Buffer' to 'string'. Callers passing number or Buffer values will fail type checking.

How detection works

For each parameter, the classifier compares the old and new type annotations. If the new type is a strict subset of the old type (e.g., the old type was a union and the new type removes members), the rule fires. Type comparison is text-based for reliability across languages.

Real-world scenario

A library function initially accepts both strings and Buffers for flexibility. In a refactor, the team removes Buffer support because it complicates the implementation. Every consumer that passes a Buffer — common in Node.js stream pipelines — will see a TypeScript compilation error.

Edge cases

  • Replacing a union type with just one of its members is always narrowing
  • Going from 'any' to a specific type is technically narrowing
  • Generic constraints narrowing is handled by R13, not R04