TypeScript 中的 JSX 详解
JSX 是一种 JavaScript 的语法扩展,允许在 JavaScript 代码中编写类似 HTML 的结构。在 TypeScript 中使用 JSX 可以获得完整的类型检查和智能提示。
1. 配置 TypeScript 支持 JSX
在 tsconfig.json
中配置 JSX 相关选项:
{"compilerOptions": {"jsx": "react-jsx", // React 17+ 新的 JSX 转换// 或 "jsx": "react-jsxdev", // 开发模式// 或 "jsx": "preserve", // 保留 JSX,由其他工具处理// 或 "jsx": "react", // 传统的 React JSX 转换"jsxFactory": "React.createElement", // 自定义 JSX 工厂函数"jsxFragmentFactory": "React.Fragment" // 自定义 Fragment 工厂}
}
2. 基本 JSX 语法
2.1 元素类型
// 内置 HTML 元素
const divElement: JSX.Element = <div>Hello</div>;// 自定义组件(PascalCase)
interface ButtonProps {onClick: () => void;children: React.ReactNode;
}const Button: React.FC<ButtonProps> = ({ onClick, children }) => {return <button onClick={onClick}>{children}</button>;
};// 使用组件
const App: React.FC = () => {return (<div><Button onClick={() => console.log('Clicked!')}>Click me</Button></div>);
};
2.2 属性类型
interface ImageProps {src: string;alt: string;width?: number;height?: number;className?: string;style?: React.CSSProperties;
}const Image: React.FC<ImageProps> = (props) => {return <img {...props} />;
};// 使用
<Image src="image.jpg" alt="Description" width={100}style={{ border: '1px solid red' }}
/>
3. 类型系统
3.1 核心类型
// JSX 元素类型
const element: JSX.Element = <div />;// 组件返回类型
const Component: React.FC = (): JSX.Element => {return <div>Hello</div>;
};// 子元素类型
interface ContainerProps {children: React.ReactNode; // 最宽松的子元素类型
}// 更具体的子元素类型
interface StrictContainerProps {children: React.ReactElement | React.ReactElement[];
}// 没有子元素
interface NoChildrenProps {children?: never;
}
3.2 事件处理
interface FormProps {onSubmit: (data: FormData) => void;onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
}const Form: React.FC<FormProps> = ({ onSubmit, onChange }) => {const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {event.preventDefault();const formData = new FormData(event.currentTarget);onSubmit(formData);};return (<form onSubmit={handleSubmit}><input type="text" onChange={onChange}name="username"/><button type="submit">Submit</button></form>);
};
4. 高级模式
4.1 条件渲染
interface UserInfoProps {user: { name: string; email: string } | null;isLoading: boolean;
}const UserInfo: React.FC<UserInfoProps> = ({ user, isLoading }) => {if (isLoading) {return <div>Loading...</div>;}if (!user) {return <div>No user found</div>;}return (<div><h1>{user.name}</h1><p>{user.email}</p></div>);
};
4.2 列表渲染
interface TodoListProps {todos: Array<{id: number;text: string;completed: boolean;}>;onToggle: (id: number) => void;
}const TodoList: React.FC<TodoListProps> = ({ todos, onToggle }) => {return (<ul>{todos.map(todo => (<li key={todo.id}style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}onClick={() => onToggle(todo.id)}>{todo.text}</li>))}</ul>);
};
4.3 插槽模式
interface CardProps {title: string;header?: React.ReactNode;footer?: React.ReactNode;children: React.ReactNode;
}const Card: React.FC<CardProps> = ({ title, header, footer, children }) => {return (<div className="card">{header && <div className="card-header">{header}</div>}<div className="card-body"><h3>{title}</h3>{children}</div>{footer && <div className="card-footer">{footer}</div>}</div>);
};// 使用
<Card title="My Card" header={<button>Close</button>}footer={<span>Footer content</span>}
>Main content here
</Card>
5. 泛型组件
interface ListProps<T> {items: T[];renderItem: (item: T) => React.ReactNode;keyExtractor: (item: T) => string | number;
}function List<T>({ items, renderItem, keyExtractor }: ListProps<T>): JSX.Element {return (<div>{items.map(item => (<div key={keyExtractor(item)}>{renderItem(item)}</div>))}</div>);
}// 使用泛型组件
interface User {id: number;name: string;
}const users: User[] = [{ id: 1, name: 'Alice' },{ id: 2, name: 'Bob' }
];<Listitems={users}keyExtractor={user => user.id}renderItem={user => <span>{user.name}</span>}
/>
6. 上下文(Context)与类型
interface Theme {mode: 'light' | 'dark';colors: {primary: string;background: string;};
}// 创建带类型的 Context
const ThemeContext = React.createContext<Theme | undefined>(undefined);interface ThemeProviderProps {theme: Theme;children: React.ReactNode;
}const ThemeProvider: React.FC<ThemeProviderProps> = ({ theme, children }) => {return (<ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>);
};// 自定义 Hook 用于消费 Context
const useTheme = (): Theme => {const theme = React.useContext(ThemeContext);if (!theme) {throw new Error('useTheme must be used within ThemeProvider');}return theme;
};
7. 高阶组件(HOC)
// 注入 props 的高阶组件
interface WithLoadingProps {isLoading: boolean;
}function withLoading<P extends object>(Component: React.ComponentType<P>
): React.FC<P & WithLoadingProps> {return ({ isLoading, ...props }: P & WithLoadingProps) => {if (isLoading) {return <div>Loading...</div>;}return <Component {...props as P} />;};
}// 使用
interface UserProfileProps {user: { name: string };
}const UserProfile: React.FC<UserProfileProps> = ({ user }) => {return <div>{user.name}</div>;
};const UserProfileWithLoading = withLoading(UserProfile);
8. 最佳实践
8.1 组件定义方式
// 1. Function Component with React.FC
const Component1: React.FC<Props> = (props) => { /* ... */ };// 2. 直接定义函数(推荐,更灵活)
function Component2(props: Props): JSX.Element { /* ... */ }// 3. 使用 PropsWithChildren(如果需要 children)
type Component3Props = React.PropsWithChildren<{title: string;
}>;const Component3: React.FC<Component3Props> = ({ title, children }) => {return (<div><h1>{title}</h1>{children}</div>);
};
8.2 事件处理类型
// 正确的类型定义
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {event.preventDefault();// 处理点击
};const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {console.log(event.target.value);
};const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {event.preventDefault();// 处理提交
};
8.3 样式类型
// CSS Properties 类型安全
const styles: React.CSSProperties = {display: 'flex',justifyContent: 'center',alignItems: 'center',backgroundColor: 'white', // 自动补全和类型检查
};// 使用
<div style={styles}>Content</div>
这些是 TypeScript 中 JSX 的核心概念和最佳实践。通过类型系统的支持,可以在开发过程中获得更好的代码提示、错误检测和重构能力。