How narrow-react-prop-types Identifies Suspect React Components: A Rule-Based Detection System

narrow-react-prop-types uses a two-stage detection workflow that combines heuristic signal scanning with live-usage verification to flag React components whose prop-type definitions describe states that never occur in production.

The narrow-react-prop-types skill in the humanlayer/skills repository is a code-analysis tool designed to tighten TypeScript prop definitions by eliminating phantom states. Its identification process, defined in SKILL.md, separates over-wide components from genuinely flexible ones through systematic signal detection followed by real-world usage validation.

Signal Detection: Spotting the Symptoms of Over-Wide Props

The first stage scans for heuristic indicators that a component's interface has been widened for convenience rather than necessity. These signals are enumerated in the "Identify the suspect component" section of the skill specification.

Key Signals That Flag Suspect Components

  • Large prop interfaces with many optional fields — interfaces where most properties use ? markers
  • Optional callback invocations — patterns like onSelect?.(...) or onArchive?.(...) suggesting handlers that may never fire
  • Fallback operators guarding always-provided values — items ?? [], count ?? 0, or && short-circuits where live code actually always supplies the value
  • UI affordances rendered unconditionally — buttons or controls shown even when their callbacks are optional
  • Demo-oriented prop shapes — props named defaultFoo, alternate handler shapes, or toggles unused by production UI

These patterns suggest the component was designed defensively for testing, Storybook, or future extensibility rather than current production needs.

Live-Usage Verification: Separating Real Code from Support Code

Once a component triggers the signal detection, the skill executes its second stage: whole-codebase analysis to classify every import and usage. This process is documented in the "Find every live usage" and "Derive the real types from the live code paths" workflow sections.

The skill categorizes call sites into two buckets:

Category Examples Used for type derivation?
Live code paths Application routes, wired components, providers, hooks, production exports Yes — these determine real prop requirements
Support code Storybook stories, tests, fixtures, mocks, demo harnesses No — these are filtered out to avoid widening types

Only live code paths inform the final narrowed prop definitions. Support code that passes extra props is identified as the source of interface bloat.

Implementation Sketch: How the Detection Logic Works

While the actual skill runs inside the Code-Layer CI agent, its logic mirrors this pattern:

// Signal detection: scanning for heuristic indicators
function findSuspectComponents(pkgRoot: string) {
  const tsFiles = globSync('**/*.tsx', { cwd: pkgRoot, absolute: true });
  const suspects: string[] = [];

  for (const file of tsFiles) {
    const src = readFileSync(file, 'utf-8');

    // Heuristic: many optional fields in Props interface
    const hasWideProps = /interface\s+\w+Props\s*{[^}]*\?/s.test(src);

    // Heuristic: optional callback chaining
    const hasOptionalCallbacks = /\w+?\.\w+?\?\(/s.test(src);

    // Heuristic: fallback operators with likely unnecessary defaults
    const hasFallbacks = /\?\?\s+/s.test(src);

    if (hasWideProps || hasOptionalCallbacks || hasFallbacks) {
      suspects.push(file);
    }
  }
  return suspects;
}

For each suspect, the skill then verifies actual usage:

// Live-usage verification: filtering to production code only
function getLiveCallSites(componentPath: string, repoRoot: string) {
  const allImports = globSync('**/*.tsx', { cwd: repoRoot, absolute: true })
    .filter(f => readFileSync(f, 'utf-8').includes(componentPath));

  // Exclude test and storybook files
  return allImports.filter(p => !/(\.test|\.stories)\.tsx$/.test(p));
}

Key Files in the Detection Architecture

The narrow-react-prop-types skill is organized across four primary files in the repository:

Summary

  • narrow-react-prop-types identifies suspect components through heuristic signal detection followed by live-usage verification.
  • Signals include optional-heavy interfaces, guarded callbacks, fallback operators, and demo-oriented prop shapes.
  • Live code paths are distinguished from support code (tests, stories) to determine which props are truly required.
  • The detection workflow is fully specified in SKILL.md and executed via the CI-agent configuration.

Frequently Asked Questions

What makes a React component "suspect" in this system?

A component becomes suspect when it exhibits patterns suggesting its prop interface was widened beyond production needs—specifically large optional interfaces, defensive fallbacks, optional callbacks, or props that only appear in tests and stories. These signals are catalogued in the skill's SKILL.md under the "Identify the suspect component" section.

How does the skill avoid narrowing props that are actually used in production?

The skill performs live-usage verification by scanning every import of the flagged component and filtering out support code—files matching patterns like *.test.tsx or *.stories.tsx. Only imports from application routes, providers, and production exports inform the final type derivation, ensuring real usage patterns are preserved.

Can this detection run automatically in CI pipelines?

Yes. The skill includes agent-narrow-component-props.yml, a CI-agent configuration file that enables automated execution. The agent maintains state across runs using narrow-component-props-memory.md and outputs formatted PR descriptions via response-template.md, making the narrowing workflow fully automatable.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →