JavaRush /Курсы /Модуль 3: React /Типизация страниц Next.js с использованием TypeScript

Типизация страниц Next.js с использованием TypeScript

Модуль 3: React
13 уровень , 4 лекция
Открыта

Интеграция TypeScript с Next.js

Чтобы использовать TypeScript в Next.js-проекте, нам нужно совсем немного повозиться — в основном это магия автоматизации:

  1. Если вы ещё не добавили TypeScript в проект, выполните следующую команду:
npm install --save-dev typescript @types/react @types/node
  1. После этого создайте пустой файл tsconfig.json в корне проекта:
touch tsconfig.json
  1. Запустите локальный сервер разработки:
npm run dev

Next.js автоматически сгенерирует tsconfig.json, настроенный под специфику Next.js. Вот пример того, как может выглядеть этот файл:

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}
  1. После успешной настройки замените файлы с расширением .js на .tsx. Теперь вы готовы к работе с TypeScript в полном объёме.

Типизация страниц в Next.js

В Next.js страницы являются React-компонентами, а TypeScript помогает нам определить типы пропсов этих компонентов. Давайте разберём это на практике.

Пример простой страницы с типизацией

Рассмотрим типизацию страницы, которая принимает в пропсах объект пользователя:

// pages/profile.tsx
import React from 'react';

// Определяем интерфейс для пропсов
interface ProfileProps {
  user: {
    id: number;
    name: string;
    email: string;
  };
}

// Объявляем компонент страницы с типами пропсов
const Profile: React.FC<ProfileProps> = ({ user }) => {
  return (
    <div>
      <h1>Привет, {user.name}!</h1>
      <p>ID: {user.id}</p>
      <p>Email: {user.email}</p>
    </div>
  );
};

export default Profile;

Здесь мы определили интерфейс ProfileProps, который описывает структуру объекта user, переданного в компонент. Теперь TypeScript будет следить, чтобы мы не передали неправильные данные.

Типизация данных на уровне getStaticProps и getServerSideProps

В Next.js функции getStaticProps и getServerSideProps используют возвращаемые данные для передачи их в компоненты страниц. Мы можем спокойно типизировать эти данные с помощью TypeScript.

Допустим, у нас есть список продуктов, который мы передаём на страницу:

// pages/products.tsx
import React from 'react';
import { GetStaticProps } from 'next';

// Интерфейс для продукта
interface Product {
  id: number;
  name: string;
  price: number;
}

// Интерфейс для пропсов страницы
interface ProductsPageProps {
  products: Product[];
}

// Статические данные для страницы
export const getStaticProps: GetStaticProps<ProductsPageProps> = async () => {
  const products = await fetch('https://api.example.com/products').then((res) =>
    res.json()
  );

  return {
    props: {
      products,
    },
  };
};

// Компонент страницы
const ProductsPage: React.FC<ProductsPageProps> = ({ products }) => {
  return (
    <div>
      <h1>Список продуктов</h1>
      <ul>
        {products.map((product) => (
          <li key={product.id}>
            {product.name} - ${product.price}
          </li>
        ))}
      </ul>
    </div>
  );
};

export default ProductsPage;

Обратите внимание, как мы типизируем результат функции getStaticProps. Теперь, если API вернёт данные, которые не соответствуют ожидаемой структуре, TypeScript сразу сообщит об ошибке.

Пример: Типизация getServerSideProps

Теперь рассмотрим типизацию для страницы, где данные загружаются на сервере перед рендерингом:

// pages/order.tsx
import React from 'react';
import { GetServerSideProps } from 'next';

// Интерфейс для заказа
interface Order {
  id: number;
  date: string;
  total: number;
}

// Интерфейс для пропсов страницы
interface OrderPageProps {
  order: Order;
}

// Получение данных о заказе на сервере
export const getServerSideProps: GetServerSideProps<OrderPageProps> = async () => {
  const order = await fetch('https://api.example.com/order/123').then((res) =>
    res.json()
  );

  return {
    props: {
      order,
    },
  };
};

// Компонент страницы
const OrderPage: React.FC<OrderPageProps> = ({ order }) => {
  return (
    <div>
      <h1>Ваш заказ</h1>
      <p>Номер заказа: {order.id}</p>
      <p>Дата заказа: {order.date}</p>
      <p>Итого: ${order.total}</p>
    </div>
  );
};

export default OrderPage;

Типизация OrderPageProps и использование её в GetServerSideProps делают наш код удобным для поддержки и обнаружения ошибок.

Типизация маршрутов в Next.js

Next.js поддерживает динамические маршруты через шаблоны в названии файлов, такие как [id].tsx. Мы можем типизировать параметры, используемые в этих маршрутах.

Рассмотрим страницу с динамическим маршрутом /product/[id]:

// pages/product/[id].tsx
import React from 'react';
import { GetStaticProps, GetStaticPaths } from 'next';
import { ParsedUrlQuery } from 'querystring';

// Интерфейс продукта
interface Product {
  id: number;
  name: string;
  price: number;
}

// Интерфейс параметров URL
interface ProductParams extends ParsedUrlQuery {
  id: string;
}

// Интерфейс для пропсов страницы
interface ProductPageProps {
  product: Product;
}

// Функция получения путей
export const getStaticPaths: GetStaticPaths<ProductParams> = async () => {
  const products = await fetch('https://api.example.com/products').then((res) =>
    res.json()
  );

  const paths = products.map((product: Product) => ({
    params: { id: product.id.toString() },
  }));

  return { paths, fallback: false };
};

// Получаем данные о продукте
export const getStaticProps: GetStaticProps<
  ProductPageProps,
  ProductParams
> = async (context) => {
  const id = context.params?.id;
  const product = await fetch(
    `https://api.example.com/products/${id}`
  ).then((res) => res.json());

  return { props: { product } };
};

// Компонент страницы
const ProductPage: React.FC<ProductPageProps> = ({ product }) => {
  return (
    <div>
      <h1>{product.name}</h1>
      <p>Цена: ${product.price}</p>
    </div>
  );
};

export default ProductPage;

Здесь мы типизировали параметры маршрута ProductParams, данные страницы ProductPageProps и функции getStaticPaths и getStaticProps.

Организация типов в Next.js

Чтобы избежать хаоса, все интерфейсы можно вынести в отдельные файлы в директорию types. Например:

/types
  product.ts
  order.ts

Теперь ваш код будет ещё более чистым и поддерживаемым.

2
Задача
Модуль 3: React, 13 уровень, 4 лекция
Недоступна
Создание и типизация простой страницы
Создание и типизация простой страницы
3
Опрос
Server-Side Rendering, 13 уровень, 4 лекция
Недоступен
Server-Side Rendering
Введение в Server-Side Rendering
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ