How narrow-react-prop-types Differentiates Real Prop Callers from Storybook and Test References

narrow-react-prop-types classifies every component import and usage as either "live code paths" or "support code" by analyzing file paths for test and Storybook patterns, ensuring that prop type narrowing is derived exclusively from production callers while forcing stories and tests to adapt to the stricter contract.

The narrow-react-prop-types skill in the humanlayer/skills repository solves the problem of prop type bloat by distinguishing between real production usage and mock-only references. By filtering out Storybook stories, test files, and mock fixtures from its analysis, the tool ensures that TypeScript prop types reflect actual runtime requirements rather than speculative test scenarios.

Classification System: Live Code vs. Support Code

Live Code Paths (Production)

Live code paths represent code that executes in production environments, including app routes, wired components, providers, and shared components. According to the workflow defined in plugins/narrow-react-prop-types/skills/narrow-react-prop-types/SKILL.md, these files are identified as existing outside known test directories and not matching patterns such as *.stories.*, *.test.*, __tests__, __mocks__, fixtures, or any path under a storybook folder. The skill explicitly instructs agents to classify call sites based on whether they represent live code paths or support scaffolding.

Support Code (Stories, Tests, and Mocks)

Support code encompasses Storybook stories, unit tests, mock fixtures, demo harnesses, and visual examples. These files are detected by matching typical naming conventions including *.stories.*, *.test.*, and *.spec.*, or by residing in folders named __mocks__, __tests__, stories, or fixtures. These patterns are excluded from the "live" set when the agent builds the usage graph to prevent test utilities from diluting the production contract.

The Four-Step Differentiation Process

The differentiation process follows a strict workflow as implemented in the agent configuration:

  1. Search for all imports and usages of the target component—including its exported prop type and any child primitives—across the entire repository.

  2. Group each call site based on its file path. Files matching support patterns are marked as support code, while all others are classified as live call sites.

  3. Analyze only live call sites to derive the real prop contract. Optional versus required decisions are based on whether every live call supplies a prop (required) or at least one live call omits it for a meaningful runtime state (optional).

  4. Force stories and tests to adapt to the narrowed contract rather than allowing them to dictate type definitions.

Implementation Details and Pattern Matching

File Path Pattern Detection

The skill uses regular expression patterns to filter support files before type analysis. The detection logic operates on file paths to categorize usage into production or scaffolding:

const supportPatterns = [
  /\.stories\./,
  /\.test\./,
  /\.spec\./,
  /__tests__/,
  /__mocks__/,
  /fixtures/,
  /storybook/,
];

function isSupportFile(filePath: string): boolean {
  return supportPatterns.some(p => p.test(filePath));
}

// Example usage in the analysis pipeline:
const usages = findAllUsages(componentName); // returns [{filePath, node}, ...]
const liveUsages = usages.filter(u => !isSupportFile(u.filePath));

Prop Analysis Logic

After isolating live usages, the skill constructs a prop usage map to determine requirement status based on actual production callers:

const propUsage = new Map<string, { required: boolean; optional: boolean }>();

liveUsages.forEach(u => {
  const suppliedProps = getSuppliedProps(u.node);
  allPropNames.forEach(p => {
    if (suppliedProps.has(p)) {
      propUsage.get(p)!.required = true;
    } else {
      propUsage.get(p)!.optional = true;
    }
  });
});

// Build the narrowed type:
type LiveProps = {
  propA: string;          // Required: present in every live call
  propB?: number | null;  // Optional: omitted in at least one live call
};

Impact on Storybook Stories

Once the narrowed contract is established from production code, support files must conform. For example, if a Storybook story previously provided undefined for an optional handler, the narrowed type might require a valid function:

// Before narrowing (invalid after analysis)
export const Default = () => <MyComponent onSelect={undefined} />;

// After narrowing (required prop enforcement)
export const Default = () => (
  <MyComponent onSelect={(id) => console.log('selected', id)} />
);

Key Source Files in the Repository

The implementation spans several files in the humanlayer/skills repository:

These resources collectively ensure that prop type tightening is driven solely by real production callers rather than test mocks or Storybook fixtures.

Summary

  • narrow-react-prop-types categorizes every component usage as either live production code or support scaffolding based on file path analysis.
  • File path patterns like *.stories.*, *.test.*, and __mocks__ automatically disqualify code from the live usage set.
  • Only live call sites determine whether props are required or optional in the narrowed TypeScript contract.
  • Storybook stories and tests are forced to adapt to the production-derived types, ensuring type safety reflects real runtime behavior rather than speculative test scenarios.

Frequently Asked Questions

What file patterns does narrow-react-prop-types recognize as test or mock files?

The skill recognizes files matching *.stories.*, *.test.*, *.spec.*, or containing __tests__, __mocks__, fixtures, or storybook in their paths. Any file matching these patterns is classified as support code and excluded from the live usage analysis that determines prop requirements.

Can Storybook stories influence the final prop types?

No. According to the SKILL.md workflow, stories and tests are explicitly treated as mock-only scaffolding and ignored for type-derivation purposes. The narrowed prop contract is derived solely from live code paths, and support files must be updated to satisfy the stricter production requirements.

How does the skill determine if a prop should be required or optional?

The skill aggregates all live call sites and checks whether every production caller supplies a specific prop. If all live instances provide the prop, it becomes required in the narrowed type. If at least one live call omits it for a valid runtime state, it remains optional or nullable in the final contract.

Where is the classification logic documented in the repository?

The classification rules are documented in plugins/narrow-react-prop-types/skills/narrow-react-prop-types/SKILL.md, specifically in the workflow section that instructs agents to "Search for all imports/usages of the component... Classify call sites by whether they are live code paths or support code."

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 →