Українська

Ознайомтеся з найкращими практиками використання 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; // Необов'язковий проп
  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)

Захисники типів — це функції, які звужують тип змінної в межах певної області видимості. Вони корисні при роботі з об'єднаними типами (union types) або коли потрібно переконатися, що змінна має певний тип перед виконанням операції.

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 є захисником типу, який перевіряє, чи є 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> використовується для типізації об'єкта події зміни (change) для елемента input. Це надає доступ до властивості 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 дозволяють використовувати стан та інші можливості React у функціональних компонентах. TypeScript бездоганно працює з хуками, забезпечуючи безпеку типів та покращений досвід розробника.

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]); // Додайте 'count' до масиву залежностей

  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 }) => {
  // Реалізуйте логіку теми тут
  return (
     {} }}>
      {children}
    
  );
};

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

  return (
    

Theme: {theme}

); }; export { ThemeProvider, MyComponent };

Надаючи тип для значення контексту, ви гарантуєте, що хук useContext поверне значення з правильним типом.

Тестування компонентів TypeScript React

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

Модульне тестування (Unit Testing)

Використовуйте фреймворки для тестування, такі як 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, для наскрізного тестування (end-to-end).

Оптимізація продуктивності

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 буде перерендерити компонент лише якщо його пропси змінилися. Це може значно покращити продуктивність, особливо для складних компонентів.

Розділення коду (Code Splitting)

Використовуйте динамічні імпорти, щоб розділити ваш код на менші частини та завантажувати їх за вимогою. Це може зменшити початковий час завантаження вашого застосунку.

import React, { Suspense } from 'react';

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

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

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

Висновок

Використання TypeScript з React може значно покращити якість, підтримуваність та масштабованість ваших веб-застосунків. Дотримуючись цих найкращих практик, ви можете використати потужність TypeScript для створення надійних та продуктивних застосунків, що відповідають потребам глобальної аудиторії. Не забувайте зосереджуватися на чітких визначеннях типів, добре структурованій організації проєкту та ретельному тестуванні для забезпечення довгострокового успіху ваших проєктів.

Додаткові ресурси