Fix: Props interface not recognized when using 'as' as a prop name
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:
- TypeScript Error: 'Props' is declared but never used
- Type Safety Loss: The generated TSX uses Record<string, any> instead of the actual Props type
- 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.