Русский

Изучите лучшие практики использования TypeScript с React для создания надежных, масштабируемых и поддерживаемых веб-приложений. Узнайте о структуре проекта, дизайне компонентов, тестировании и оптимизации.

TypeScript с React: лучшие практики для масштабируемых и поддерживаемых приложений

TypeScript и React - мощная комбинация для создания современных веб-приложений. TypeScript привносит статическую типизацию в JavaScript, улучшая качество кода и упрощая поддержку, в то время как React предоставляет декларативный и компонентный подход к созданию пользовательских интерфейсов. Этот пост в блоге посвящен лучшим практикам использования TypeScript с React для создания надежных, масштабируемых и поддерживаемых приложений, подходящих для глобальной аудитории.

Зачем использовать TypeScript с React?

Прежде чем перейти к лучшим практикам, давайте разберемся, почему TypeScript является ценным дополнением к разработке React:

Настройка проекта TypeScript React

Использование Create React App

Самый простой способ начать новый проект TypeScript React - использовать Create React App с шаблоном TypeScript:

npx create-react-app my-typescript-react-app --template typescript

Эта команда создает базовый проект React с настроенным TypeScript, включая необходимые зависимости и файл tsconfig.json.

Настройка tsconfig.json

Файл tsconfig.json - это сердце вашей конфигурации TypeScript. Вот некоторые рекомендуемые настройки:

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

Ключевые параметры, которые следует учитывать:

Лучшие практики для компонентов React с TypeScript

Типизация свойств компонента

Одним из наиболее важных аспектов использования TypeScript с React является правильная типизация свойств ваших компонентов. Используйте интерфейсы или псевдонимы типов, чтобы определить форму объекта свойств.

interface MyComponentProps {
  name: string;
  age?: number; // Optional prop
  onClick: () => void;
}

const MyComponent: React.FC = ({ name, age, onClick }) => {
  return (
    

Hello, {name}!

{age &&

You are {age} years old.

}
); };

Использование React.FC<MyComponentProps> гарантирует, что компонент является функциональным компонентом и что свойства правильно типизированы.

Типизация состояния компонента

Если вы используете компоненты классов, вам также необходимо типизировать состояние компонента. Определите интерфейс или псевдоним типа для объекта состояния и используйте его в определении компонента.

interface MyComponentState {
  count: number;
}

class MyComponent extends React.Component<{}, MyComponentState> {
  state: MyComponentState = {
    count: 0
  };

  handleClick = () => {
    this.setState({
      count: this.state.count + 1
    });
  };

  render() {
    return (
      

Count: {this.state.count}

); } }

Для функциональных компонентов, использующих хук useState, TypeScript часто может определить тип переменной состояния, но вы также можете явно указать его:

import React, { useState } from 'react';

const MyComponent: React.FC = () => {
  const [count, setCount] = useState(0);

  return (
    

Count: {count}

); };

Использование Type Guards

Type guards - это функции, которые сужают тип переменной в определенной области. Они полезны при работе с объединениями типов или когда вам необходимо убедиться, что переменная имеет определенный тип перед выполнением операции.

interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  side: number;
}

type Shape = Circle | Square;

function isCircle(shape: Shape): shape is Circle {
  return shape.kind === "circle";
}

function getArea(shape: Shape): number {
  if (isCircle(shape)) {
    return Math.PI * shape.radius ** 2;
  } else {
    return shape.side ** 2;
  }
}

Функция isCircle - это type guard, который проверяет, является ли Shape Circle. Внутри блока if TypeScript знает, что shape - это Circle, и позволяет вам получить доступ к его свойству radius.

Обработка событий

При обработке событий в React с TypeScript важно правильно типизировать объект события. Используйте соответствующий тип события из пространства имен React.

const MyComponent: React.FC = () => {
  const handleChange = (event: React.ChangeEvent) => {
    console.log(event.target.value);
  };

  return (
    
  );
};

В этом примере React.ChangeEvent<HTMLInputElement> используется для типизации объекта события для события изменения в элементе ввода. Это обеспечивает доступ к свойству target, которое является HTMLInputElement.

Структура проекта

Хорошо структурированный проект имеет решающее значение для удобства обслуживания и масштабируемости. Вот предлагаемая структура проекта для приложения TypeScript React:

src/
├── components/
│   ├── MyComponent/
│   │   ├── MyComponent.tsx
│   │   ├── MyComponent.module.css
│   │   └── index.ts
├── pages/
│   ├── HomePage.tsx
│   └── AboutPage.tsx
├── services/
│   ├── api.ts
│   └── auth.ts
├── types/
│   ├── index.ts
│   └── models.ts
├── utils/
│   ├── helpers.ts
│   └── constants.ts
├── App.tsx
├── index.tsx
├── react-app-env.d.ts
└── tsconfig.json

Ключевые моменты:

Использование хуков с TypeScript

React Hooks позволяют использовать состояние и другие функции React в функциональных компонентах. TypeScript легко работает с Hooks, обеспечивая безопасность типов и улучшенный опыт разработчика.

useState

Как показано ранее, вы можете явно типизировать переменную состояния при использовании useState:

import React, { useState } from 'react';

const MyComponent: React.FC = () => {
  const [count, setCount] = useState(0);

  return (
    

Count: {count}

); };

useEffect

При использовании useEffect помните о массиве зависимостей. TypeScript может помочь вам выявить ошибки, если вы забудете включить зависимость, которая используется внутри эффекта.

import React, { useState, useEffect } from 'react';

const MyComponent: React.FC = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]); // Add 'count' to the dependency array

  return (
    

Count: {count}

); };

Если вы опустите count из массива зависимостей, эффект будет запущен только один раз при монтировании компонента, и заголовок документа не будет обновляться при изменении количества. TypeScript предупредит вас об этой потенциальной проблеме.

useContext

При использовании useContext вам необходимо указать тип для значения контекста.

import React, { createContext, useContext } from 'react';

interface ThemeContextType {
  theme: string;
  toggleTheme: () => void;
}

const ThemeContext = createContext(undefined);

const ThemeProvider: React.FC = ({ children }) => {
  // Implement theme logic here
  return (
     {} }}>
      {children}
    
  );
};

const MyComponent: React.FC = () => {
  const { theme, toggleTheme } = useContext(ThemeContext) as ThemeContextType;

  return (
    

Theme: {theme}

); }; export { ThemeProvider, MyComponent };

Указав тип для значения контекста, вы убедитесь, что хук useContext возвращает значение с правильным типом.

Тестирование компонентов TypeScript React

Тестирование является важной частью создания надежных приложений. TypeScript улучшает тестирование, обеспечивая безопасность типов и улучшенное покрытие кода.

Модульное тестирование

Используйте платформы тестирования, такие как Jest и React Testing Library, для модульного тестирования ваших компонентов.

// MyComponent.test.tsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  it('renders the component with the correct name', () => {
    render();
    expect(screen.getByText('Hello, John!')).toBeInTheDocument();
  });

  it('calls the onClick handler when the button is clicked', () => {
    const onClick = jest.fn();
    render();
    fireEvent.click(screen.getByRole('button'));
    expect(onClick).toHaveBeenCalledTimes(1);
  });
});

Проверка типов TypeScript помогает выявлять ошибки в ваших тестах, такие как передача неверных свойств или использование неверных обработчиков событий.

Интеграционное тестирование

Интеграционные тесты проверяют, правильно ли работают вместе различные части вашего приложения. Используйте такие инструменты, как Cypress или Playwright, для сквозного тестирования.

Оптимизация производительности

TypeScript также может помочь с оптимизацией производительности, выявляя потенциальные узкие места производительности на ранних этапах процесса разработки.

Мемоизация

Используйте React.memo для мемоизации функциональных компонентов и предотвращения ненужных повторных рендерингов.

import React from 'react';

interface MyComponentProps {
  name: string;
}

const MyComponent: React.FC = ({ name }) => {
  console.log('Rendering MyComponent');
  return (
    

Hello, {name}!

); }; export default React.memo(MyComponent);

React.memo будет повторно отображать компонент только в том случае, если свойства изменились. Это может значительно повысить производительность, особенно для сложных компонентов.

Разделение кода

Используйте динамические импорты, чтобы разделить свой код на более мелкие фрагменты и загружать их по запросу. Это может сократить время начальной загрузки вашего приложения.

import React, { Suspense } from 'react';

const MyComponent = React.lazy(() => import('./MyComponent'));

const App: React.FC = () => {
  return (
    Loading...
}> ); };

React.lazy позволяет динамически импортировать компоненты, которые загружаются только при необходимости. Компонент Suspense предоставляет резервный пользовательский интерфейс во время загрузки компонента.

Заключение

Использование TypeScript с React может значительно улучшить качество, удобство обслуживания и масштабируемость ваших веб-приложений. Следуя этим лучшим практикам, вы можете использовать мощь TypeScript для создания надежных и производительных приложений, отвечающих потребностям глобальной аудитории. Не забывайте уделять особое внимание четким определениям типов, хорошо структурированной организации проектов и тщательному тестированию, чтобы обеспечить долгосрочный успех ваших проектов.

Дополнительные ресурсы