compiler icon indicating copy to clipboard operation
compiler copied to clipboard

Fix: Props interface not recognized when using 'as' as a prop name

Open jp-knj opened this issue 4 months ago • 3 comments

Closes #927

Background

Polymorphic components are a common pattern in modern web development where a component can render as different HTML elements. The as prop is the standard convention for this pattern:

---
interface Props {
  as?: string;
  href?: string;
}

const { as: Component = 'div', href } = Astro.props;
---

<Component href={href}>
  <slot />
</Component>

This pattern allows users to create flexible components that can adapt their rendered element based on usage context.

Problem

When using as as a prop name, the Astro compiler fails to recognize that the Props interface is being used, resulting in:

  1. TypeScript Error: 'Props' is declared but never used
  2. Type Safety Loss: The generated TSX uses Record<string, any> instead of the actual Props type
  3. Developer Experience: False positive errors that require awkward workarounds

Root Cause

The issue stems from the compiler's Props detection logic (GetPropsType in js_scanner.go). When processing the code, it encounters the as keyword and incorrectly assumes it's part of an import alias pattern (import { Props as Something }), causing it to reset the Props detection.

The compiler didn't distinguish between:

  • Import aliasing context: import { Props as Something } → should reset Props
  • Object destructuring context: const { as: Component } → should NOT reset Props

This bug was introduced as a side effect of fixing #814, which added support for Props import aliasing but was too aggressive in its pattern matching.

Changes

  • Fixes Props interface being incorrectly marked as "unused" when using as as a prop name
  • Adds context checking to distinguish between:
    • Import aliasing: import { Props as Something }
    • Property destructuring: const { as: Component } = Astro.props

Before:

// TSX output when using 'as' prop:
export default function Component(_props: Record<string, any>): any {}
// ❌ TypeScript error: 'Props' is declared but never used

After:

// TSX output when using 'as' prop:
export default function Component(_props: Props): any {}
// ✅ Props correctly recognized

Testing

  • Added comprehensive test cases for Props detection with 'as' prop name
  • Tests cover both with and without type assertions
  • Manually verified TSX output generates correct Props type

Docs

Bug fix only - no documentation changes needed. The compiler now correctly handles a previously broken edge case.

jp-knj avatar Aug 23 '25 17:08 jp-knj