# Add Parameter

> Give a method a new parameter when it needs data it cannot reach, migrating callers through a temporary overload or default value.

- kind: technique
- category: simplifying-method-calls
- aliases: Change Function Declaration
- canonical: https://aipatterns.dev/refactoring/techniques/add-parameter
- inspired-by: https://refactoring.guru/add-parameter

## Problem

A method needs information it does not have. It reaches for a global, reads a field that only some callers set, or silently assumes a default that is wrong for some of them.

## Solution

**Add a parameter that carries the needed value and pass it from every caller.** Use a default value or an overload to migrate callers safely, then remove the default if every caller should choose explicitly.

## Before

```ts
function formatInvoiceTotal(invoice: Invoice): string {
  // Always formatted for the US, even for EU customers
  return new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: invoice.currency,
  }).format(invoice.totalCents / 100);
}

renderPdf({ total: formatInvoiceTotal(invoice) });
```

## After

```ts
function formatInvoiceTotal(invoice: Invoice, locale: string): string {
  return new Intl.NumberFormat(locale, {
    style: "currency",
    currency: invoice.currency,
  }).format(invoice.totalCents / 100);
}

renderPdf({ total: formatInvoiceTotal(invoice, customer.locale) });
```

## Why

- The dependency becomes explicit at the call site, so readers and tests can see and control it.
- It avoids hidden coupling to globals or ambient state.

## Steps

1. Check whether the method can compute the value itself from what it already has. If so, do that instead; see [Replace Parameter with Method Call](https://aipatterns.dev/refactoring/techniques/replace-parameter-with-method-call.md).
2. Add the parameter with a default equal to today's behavior (`locale = "en-US"`). Run the tests; nothing changes.
3. Update callers one at a time to pass the real value. Run the tests after each batch.
4. When every caller passes the argument, remove the default so new callers must decide. Run the type checker and tests.
5. For overridden methods, add the parameter to every override and interface declaration in the same step.

## Watch out

- Do not add a parameter if the method already has many. Group related data with [Introduce Parameter Object](https://aipatterns.dev/refactoring/techniques/introduce-parameter-object.md) or pass the source object with [Preserve Whole Object](https://aipatterns.dev/refactoring/techniques/preserve-whole-object.md).
- A boolean parameter that switches the method's behavior is a smell. Prefer two methods; see [Replace Parameter with Explicit Methods](https://aipatterns.dev/refactoring/techniques/replace-parameter-with-explicit-methods.md).
- In JavaScript and TypeScript, adding a positional parameter before existing optional ones silently shifts arguments. Add new parameters at the end, or switch to an options object.
- Leaving a permanent default can hide callers that should have made a choice.
- The inverse technique is [Remove Parameter](https://aipatterns.dev/refactoring/techniques/remove-parameter.md).

## Related

- Inverse: [Remove Parameter](https://aipatterns.dev/refactoring/techniques/remove-parameter.md).
- Alternatives when the list grows: [Introduce Parameter Object](https://aipatterns.dev/refactoring/techniques/introduce-parameter-object.md), [Preserve Whole Object](https://aipatterns.dev/refactoring/techniques/preserve-whole-object.md).
- Can lead to [Long Parameter List](https://aipatterns.dev/refactoring/smells/long-parameter-list.md) if overused.

## Agent checklist

- [ ] The method cannot derive the value from data it already holds.
- [ ] The parameter list stays short (about four or fewer), or you used a parameter object.
- [ ] Every override and interface declaration got the parameter.
- [ ] Temporary defaults were removed once all callers were migrated, unless a default is genuinely correct.
