Astro calendar_today 23 апр. 2026 г. schedule 2 мин

Astro + TypeScript: Типизация проекта с нуля

Как использовать TypeScript в Astro.js: настройка tsconfig, типизация компонентов и пропсов, Content Collections с Zod, typed env-переменные и API-роуты.

person
Журналист
Автор
Astro + TypeScript — типизация и настройка

Astro имеет встроенную поддержку TypeScript — никаких плагинов не нужно. .astro-файлы, .ts, .tsx работают из коробки с полным автодополнением и проверкой типов. Разбираем, как настроить типизацию правильно.

TypeScript в Astro по умолчанию

Astro использует TypeScript внутри frontmatter (блок ---) и во всех .ts/.tsx-файлах. Файлы .astro — это TypeScript + HTML в одном флаконе.

code
---
// Полный TypeScript здесь
interface Props {
  title: string;
  count?: number;
  onAction?: () => void;
}

const { title, count = 0 } = Astro.props;

// Типизированные данные из Content Collections
import { getCollection } from 'astro:content';
const articles = await getCollection('articles');
// articles — CollectionEntry<'articles'>[] — полный тип
---

<h1>{title}</h1>
<p>{count} статей</p>

Конфигурация tsconfig.json

code
{
  "extends": "astro/tsconfigs/strict",
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@components/*": ["src/components/*"],
      "@layouts/*": ["src/layouts/*"],
      "@lib/*": ["src/lib/*"],
      "@assets/*": ["src/assets/*"]
    },
    "strictNullChecks": true,
    "noUncheckedIndexedAccess": true
  },
  "include": ["src/**/*", "astro.config.mjs"],
  "exclude": ["node_modules", "dist"]
}

Astro предоставляет три базовых пресета:

  • astro/tsconfigs/base — минимум
  • astro/tsconfigs/strict — строгий (рекомендуется)
  • astro/tsconfigs/strictest — максимально строгий

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

code
---
// src/components/ArticleCard.astro
interface Props {
  title: string;
  description: string;
  slug: string;
  date?: Date;
  tags?: string[];
  featured?: boolean;
}

// Деструктуризация с дефолтными значениями
const { title, description, slug, date, tags = [], featured = false } = Astro.props;

// Форматирование даты — TypeScript знает, что date может быть undefined
const formattedDate = date?.toLocaleDateString('ru-RU', {
  year: 'numeric',
  month: 'long',
  day: 'numeric',
});
---

<article class:list={['card', { 'card--featured': featured }]}>
  <h2><a href={`/articles/${slug}/`}>{title}</a></h2>
  <p>{description}</p>
  {formattedDate && <time datetime={date?.toISOString()}>{formattedDate}</time>}
  <ul>
    {
      tags.map((tag) => (
        <li>
          <a href={`/tags/${tag}/`}>{tag}</a>
        </li>
      ))
    }
  </ul>
</article>

Типизация Content Collections

Content Collections генерируют типы автоматически на основе content.config.ts:

code
// src/content.config.ts
import { defineCollection, z } from 'astro:content';

const articles = defineCollection({
  schema: z.object({
    title: z.string(),
    description: z.string(),
    date: z.coerce.date(),
    tags: z.array(z.string()).default([]),
    draft: z.boolean().default(false),
    readingTime: z.number().optional(), // Минуты чтения
  }),
});

export const collections = { articles };
code
---
import { getCollection, type CollectionEntry } from 'astro:content';

// Полный тип: CollectionEntry<'articles'>
const articles: CollectionEntry<'articles'>[] = await getCollection('articles');

// article.data полностью типизирован
const firstArticle = articles[0];
// firstArticle.data.title — string ✅
// firstArticle.data.date — Date ✅
// firstArticle.data.readingTime — number | undefined ✅
// firstArticle.data.unknownField — ошибка TypeScript ✅
---

Типизация env-переменных

code
// src/env.d.ts
/// <reference types="astro/client" />

interface ImportMetaEnv {
  readonly PUBLIC_SITE_URL: string;
  readonly PUBLIC_PB_URL: string;
  readonly PB_EMAIL: string; // Серверный (без PUBLIC_)
  readonly PB_PASSWORD: string;
  readonly STRIPE_SECRET_KEY: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

Теперь import.meta.env.PUBLIC_SITE_URL — строка с автодополнением. Обращение к несуществующей переменной — ошибка TS.

Утилитарные типы для Astro

code
// src/lib/types.ts

// Тип пропсов компонента из его Props interface
import type { ComponentProps } from 'astro/types';
import ArticleCard from '@components/ArticleCard.astro';
type ArticleCardProps = ComponentProps<typeof ArticleCard>;

// Создайте общие типы для переиспользования
export type Color = 'primary' | 'secondary' | 'tertiary';

export interface NavItem {
  label: string;
  href: string;
  icon?: string;
  external?: boolean;
}

export interface SiteConfig {
  name: string;
  description: string;
  url: string;
  author: string;
  social: {
    github?: string;
    telegram?: string;
    twitter?: string;
  };
}

TypeScript в API-роутах

code
// src/pages/api/contact.ts
import type { APIRoute } from 'astro';
import { z } from 'astro/zod';

// Zod-схема для входных данных
const ContactSchema = z.object({
  name: z.string().min(2).max(100),
  email: z.string().email(),
  message: z.string().min(10).max(2000),
});

export const POST: APIRoute = async ({ request }) => {
  const body = await request.json();

  // Валидация
  const result = ContactSchema.safeParse(body);
  if (!result.success) {
    return new Response(JSON.stringify({ error: result.error.flatten() }), {
      status: 400,
    });
  }

  // Типизированные данные
  const { name, email, message } = result.data;

  // Обработка...
  console.log(`Письмо от ${name} (${email}): ${message}`);

  return new Response(JSON.stringify({ ok: true }), { status: 200 });
};
verified

Zod везде

Используйте Zod не только в Content Collections, но и для валидации форм, API-запросов и переменных окружения. Astro включает Zod нативно.

security

Strict mode

astro/tsconfigs/strict включает noUncheckedIndexedAccess — это защищает от ошибок при работе с массивами (array[0] может быть undefined).

link

Пути через @

Настройте алиасы @components/*, @lib/* в tsconfig и astro.config. Избавит от ../../../components/Header.astro в импортах.

Проверка типов

code
# Проверить типы без сборки
npx astro check

# В CI/CD — выход с ошибкой при TS-ошибках
npx astro check && echo "Types OK"

Добавьте в package.json:

code
{
  "scripts": {
    "check": "astro check",
    "build": "astro check && astro build"
  }
}

Частые вопросы

Можно ли не использовать TypeScript в Astro? Да, файлы .js и .jsx работают. Но VS Code и WebStorm дают автодополнение и подсказки только при TypeScript.

Как типизировать импорт изображений?

code
import myImage from '../assets/image.png';
// myImage — ImageMetadata { src, width, height, format }

Как проверить тип пропсов в runtime? Используйте Zod внутри frontmatter:

code
import { z } from 'astro/zod';
const schema = z.object({ title: z.string() });
const props = schema.parse(Astro.props); // Выбросит исключение при ошибке

Итог

TypeScript в Astro работает из коробки и требует минимальной настройки. Строгая типизация + Zod для Content Collections + типизированные env-переменные — это защита от целого класса runtime-ошибок прямо на этапе разработки. Начните с astro/tsconfigs/strict и добавляйте типы постепенно.

Портрет автора Дмитрий Соколов

Senior Frontend Engineer / Tech Writer

Senior Frontend Engineer с 9-летним опытом. Специализируется на Astro.js и JAMstack.

Комментарии

Загрузка комментариев...

Оставить комментарий

Комментарии проходят модерацию перед публикацией. Правила

Рекомендуем к прочтению