javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > TypeScript JSX使用

TypeScript中JSX的使用小结

作者:心随雨下

本文主要介绍了TypeScript中JSX的使用小结, 使用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' }
];

<List
  items={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 的核心概念和最佳实践。通过类型系统的支持,可以在开发过程中获得更好的代码提示、错误检测和重构能力。

到此这篇关于TypeScript中JSX的使用小结的文章就介绍到这了,更多相关TypeScript JSX使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文