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?.(...)oronArchive?.(...)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:
-
SKILL.md— [plugins/narrow-react-prop-types/skills/narrow-react-prop-types/SKILL.md](https://github.com/humanlayer/skills/blob/main/plugins/narrow-react-prop-types/skills/narrow-react-prop-types/SKILL.md): The human-readable specification defining the complete detection workflow, signal list, and live-usage classification rules. -
agent-narrow-component-props.yml— [plugins/narrow-react-prop-types/skills/narrow-react-prop-types/references/agent-narrow-component-props.yml](https://github.com/humanlayer/skills/blob/main/plugins/narrow-react-prop-types/skills/narrow-react-prop-types/references/agent-narrow-component-props.yml): CI-agent configuration that automates skill execution. -
narrow-component-props-memory.md— [plugins/narrow-react-prop-types/skills/narrow-react-prop-types/references/narrow-component-props-memory.md](https://github.com/humanlayer/skills/blob/main/plugins/narrow-react-prop-types/skills/narrow-react-prop-types/references/narrow-component-props-memory.md): Persistent memory file for storing intermediate findings across agent runs. -
response-template.md— [plugins/narrow-react-prop-types/skills/narrow-react-prop-types/references/response-template.md](https://github.com/humanlayer/skills/blob/main/plugins/narrow-react-prop-types/skills/narrow-react-prop-types/references/response-template.md): Template formatting the final PR body after prop types are narrowed.
Summary
narrow-react-prop-typesidentifies 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.mdand 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →