Skip to main content

TypeScript analyzer

Class Shape

Reports class responsibility load: large classes by instance-method count, and low-cohesion classes whose stateful methods split into disconnected clusters over the instance fields.

patterns ts-class-shape

Class Shape

Reports class responsibility load: large classes by instance-method count, and low-cohesion classes whose stateful methods split into disconnected clusters over the instance fields.

Modern node TypeScript rarely inherits; its responsibility problems live in flat service classes that grow one method at a time. This analysis reports the two signals that survived calibration against real code (the Phase 7 design-principle memo): size, as the instance-method count, and cohesion, as the number of clusters the STATEFUL methods form when two methods are connected by a shared field or a call. Both are informational and unscored — they rank what to examine first. The false positives that make naive cohesion metrics useless are excluded by construction: stateless helper methods belong to no cluster, a two-method satellite is not a responsibility, and a facade (almost every method forwards one call to a collaborator held on this) is reported as large with its delegation noted rather than as a split. Inherited fields are not visible to this per-file pass.

Severity guide

info
Both insights are informational: a ranking aid, never a defect verdict or a score penalty.
warning
Not currently emitted by this analysis.
critical
Not currently emitted by this analysis.

Examples

Before

class ReportService {
  private cache = new Map();
  private readonly mailer: Mailer;
  buildSummary() { /* uses this.cache */ }
  invalidate() { /* uses this.cache */ }
  formatRow() { /* uses this.cache */ }
  send() { /* uses this.mailer */ }
  retry() { /* uses this.mailer */ }
  schedule() { /* uses this.mailer */ }
}

After

class ReportBuilder { private cache = new Map(); buildSummary() {} invalidate() {} formatRow() {} }
class ReportMailer { constructor(private readonly mailer: Mailer) {} send() {} retry() {} schedule() {} }

The six stateful methods form two clusters that never share a field or a call — two responsibilities under one name. Extracting each cluster with its fields makes the seam explicit.

Remediation

Group methods by the fields they share; extract each group that stands alone; keep facades as facades.

For a large class, read the methods as field-sharing groups — the low-cohesion insight names the groups when they are disconnected. Extract each group with its fields into its own class and let the original hold only what the groups share. If most methods touch no field, prefer free functions: they test and tree-shake better than a bag of stateless methods. A facade that forwards to many collaborators is one responsibility (coordination); the responsibilities to examine are the collaborators behind it.

Documentation