TypeScript интеграция

Fresh — это современный веб-фреймворк для разработки на Deno, ориентированный на высокую производительность и использование современных возможностей JavaScript и TypeScript. Встроенная поддержка TypeScript делает его особенно удобным для крупных проектов, где важна статическая типизация, автодополнение и безопасность кода.

Настройка TypeScript в Fresh

Fresh изначально поддерживает TypeScript без необходимости дополнительной конфигурации. Любой файл с расширением .ts или .tsx автоматически обрабатывается Deno и Fresh. Для полноценного контроля над компиляцией и настройками проекта используется файл tsconfig.json.

Пример минимальной конфигурации:

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "strict": true,
    "jsx": "react-jsx",
    "jsxImportSource": "preact",
    "moduleResolution": "Node",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
  },
  "exclude": ["node_modules", "dist"]
}

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

  • jsx: "react-jsx" и jsxImportSource: "preact" — позволяет использовать JSX с Preact, который лежит в основе Fresh.
  • strict: true — включает строгий режим TypeScript, обеспечивая полную проверку типов.
  • moduleResolution: "Node" — облегчает работу с внешними модулями.

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

В Fresh компоненты создаются как функции, возвращающие JSX. Для TypeScript важно корректно типизировать пропсы компонентов.

Пример компонента:

/** @jsx h */
import { h } from "preact";
import { ComponentChildren } from "preact";

interface ButtonProps {
  label: string;
  onClick: () => void;
}

export default function Button({ label, onClick }: ButtonProps) {
  return (
    <button onCl ick={onClick}>
      {label}
    </button>
  );
}

Особенности:

  • ComponentChildren позволяет типизировать дочерние элементы компонентов.
  • TypeScript проверяет правильность передачи пропсов при использовании компонента: ошибки выявляются ещё на этапе компиляции.

Типизация маршрутов и обработчиков

Fresh использует файловую структуру для маршрутов. Файлы в папке routes автоматически становятся обработчиками HTTP-запросов. Для TypeScript удобно использовать интерфейсы и типы из Request и Response.

Пример маршрута:

import { Handlers } from "$fresh/server.ts";

interface Data {
  message: string;
}

export const handler: Handlers<Data> = {
  GET(req, ctx) {
    return new Response(JSON.stringify({ message: "Hello, Fresh!" }), {
      headers: { "Content-Type": "application/json" },
    });
  },
};

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

  • Handlers<Data> обеспечивает типизацию возвращаемых данных.
  • ctx может содержать информацию о маршруте и контексте запроса, типизировать его можно с помощью собственных интерфейсов.

Типизация состояния и хуков

Fresh поддерживает хранилище состояния через хуки, совместимые с Preact. TypeScript помогает избежать ошибок при работе с состоянием компонентов.

Пример использования состояния:

import { useState } from "preact/hooks";

export default function Counter() {
  const [count, setCount] = useState<number>(0);

  return (
    <div>
      <p>Счётчик: {count}</p>
      <button onCl ick={() => setCount(count + 1)}>Увеличить</button>
    </div>
  );
}

Особенности:

  • <number> указывает тип состояния, предотвращая случайное присваивание строк или других типов.
  • TypeScript автоматически подсказывает методы и типы состояния.

Использование внешних типов и библиотек

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

Пример:

import { oak } from "https://deno.land/x/oak@v12.5.0/mod.ts";

interface ContextState {
  user?: string;
}

const app = new oak.Application<ContextState>();

Особенности:

  • Интерфейсы позволяют расширять контекст фреймворка и интегрировать сторонние модули.
  • TypeScript контролирует корректность типов при использовании библиотек.

Рекомендации по структуре TypeScript-проектов

  1. Разделение типов: хранить все интерфейсы и типы в отдельной папке types.
  2. Явная типизация: использовать interface и type для пропсов компонентов и данных API.
  3. Использование строгого режима: strict: true помогает обнаружить ошибки ещё на этапе компиляции.
  4. Модули и алиасы: для удобства навигации подключать алиасы через paths в tsconfig.json.

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

TypeScript упрощает написание тестов, обеспечивая корректность типов входных и выходных данных:

import { assertEquals } from "https://deno.land/std@0.212.0/testing/asserts.ts";

Deno.test("GET /api returns correct message", async () => {
  const res = await fetch("http://localhost:8000/api");
  const data = await res.json();
  assertEquals(data.message, "Hello, Fresh!");
});

Преимущества:

  • Типизация JSON-ответов предотвращает ошибки при обработке данных.
  • Совместимость с Deno тестовым фреймворком без дополнительных настроек.

Итог

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