R04BREAKINGfunctionParameter 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