React+styled-components+TypeScript中BEM风格命名的类型错误求助
Got it, let's fix those TypeScript errors you're seeing with your BEM-like styled-components setup. The root issue is that TypeScript doesn't automatically know about the static header property you're adding to your Card component—we need to explicitly define custom types to make this work properly.
Here's a step-by-step solution:
Step 1: Define Custom Types for Your Card Component
First, create interfaces and types to describe the full shape of your Card component, including its sub-components. This tells TypeScript exactly what properties to expect on the Card object.
import styled from 'styled-components'; // 1. Define the structure of your Card's sub-components interface CardSubComponents { header: typeof Header; // Add other sub-components here (e.g., footer, content) if needed } // 2. Create a combined type that merges the base styled component with our sub-components type CardComponent = typeof CardContainer & CardSubComponents;
Step 2: Build Your Base Card Container and Sub-Components
Create your core Card container and its sub-components like you normally would with styled-components:
// Base Card container const CardContainer = styled.div` border: 1px solid #e0e0e0; border-radius: 8px; padding: 1.5rem; max-width: 400px; `; // Header sub-component (BEM-like Card__header) const Header = styled.h1` font-size: 1.25rem; margin: 0 0 1rem 0; color: #333; `;
Step 3: Attach Sub-Components to the Base Card
Cast the base CardContainer to our custom CardComponent type, then attach the sub-component. This resolves the "Type 'StyledComponent<...>' is not assignable to type 'never'" error.
// Cast the container to our custom type to enable adding sub-components const Card = CardContainer as CardComponent; Card.header = Header; // Export the complete Card component export default Card;
Step 4: Use the Component in App.tsx
Now you can use <Card.header> without the "JSX element type 'Card.header' does not have any construct or call signatures" error:
import Card from './card'; function App() { return ( <div style={{ padding: '2rem' }}> <Card> <Card.header>Header</Card.header> <p>Card content goes here</p> </Card> </div> ); } export default App;
Why This Works
- The
CardSubComponentsinterface explicitly declares that ourCardcomponent has aheaderproperty matching the type of ourHeaderstyled component. - The
CardComponenttype merges the base styled component type with our sub-components interface, so TypeScript recognizes both the component itself and its static properties. - Casting
CardContainertoCardComponentallows us to safely attach sub-components without TypeScript throwing type mismatch errors.
If you need to add more sub-components (like Card.footer or Card.content), just extend the CardSubComponents interface and repeat the attachment step.
内容的提问来源于stack exchange,提问作者lomine

