# Inline Class

> Fold a class that does too little into the class that uses it, moving its fields and methods across and deleting it.

- kind: technique
- category: moving-features-between-objects
- canonical: https://aipatterns.dev/refactoring/techniques/inline-class
- inspired-by: https://refactoring.guru/inline-class

## Problem

A class holds one or two fields and a method or two, and only one other class uses it. It may be a leftover from an earlier split or a placeholder for growth that never came. Every reader has to open a second file to find almost nothing.

## Solution

**Move all of the small class's features into its single user, then delete it.**

## Before

```ts
class ReportSchedule {
  constructor(private cron: CronSpec, private timezone: string) {}

  nextRunAfter(now: Date): Date {
    return this.cron.next(now, this.timezone);
  }
}

class ScheduledReport {
  constructor(
    public id: string,
    public query: string,
    private schedule: ReportSchedule,
  ) {}

  nextRunAfter(now: Date): Date {
    return this.schedule.nextRunAfter(now);
  }
}
```

## After

```ts
class ScheduledReport {
  constructor(
    public id: string,
    public query: string,
    private cron: CronSpec,
    private timezone: string,
  ) {}

  nextRunAfter(now: Date): Date {
    return this.cron.next(now, this.timezone);
  }
}
```

## Why

- One less type and file to navigate. The schedule logic sits where it is used.
- Removes a delegating method that added no behavior.
- Inlining two poorly divided classes can also be the first step toward re-splitting them along a better line.

## Steps

1. Confirm the class has one user, or that every user can be redirected. Check for uses in DI configuration, serialization and tests.
2. In the absorbing class, create public members for each public member of the small class. Make them delegate. Run the tests.
3. Redirect external callers of the small class to the absorbing class. Run the tests.
4. Move fields and methods across with [Move Field](https://aipatterns.dev/refactoring/techniques/move-field.md) and [Move Method](https://aipatterns.dev/refactoring/techniques/move-method.md), one at a time.
5. Delete the small class. Run the tests.

## Watch out

- Don't inline a class that several unrelated classes use, or that models a real domain concept with invariants (a `Money`, an `EmailAddress`). Small is not the same as useless.
- Don't inline when the class sits on a module or package boundary that exists for a reason, such as dependency direction or a published API.
- Inlining can bloat the receiver. If it is already a [Large Class](https://aipatterns.dev/refactoring/smells/large-class.md), look for a better home.
- The inverse is [Extract Class](https://aipatterns.dev/refactoring/techniques/extract-class.md).

## Related

- Fixes [Lazy Class](https://aipatterns.dev/refactoring/smells/lazy-class.md) and [Speculative Generality](https://aipatterns.dev/refactoring/smells/speculative-generality.md).
- Inverse: [Extract Class](https://aipatterns.dev/refactoring/techniques/extract-class.md).
- [Inline Method](https://aipatterns.dev/refactoring/techniques/inline-method.md) is the method-level counterpart; [Remove Middle Man](https://aipatterns.dev/refactoring/techniques/remove-middle-man.md) handles classes that only delegate.

## Agent checklist

- [ ] The class has no independent domain meaning or invariants worth naming.
- [ ] Every user, including configuration, serializers and tests, was found and redirected.
- [ ] Features moved one at a time with tests green after each.
- [ ] The absorbing class did not become a Large Class.
- [ ] The inlined class is deleted.
