Astro имеет встроенную поддержку TypeScript — никаких плагинов не нужно. .astro-файлы, .ts, .tsx работают из коробки с полным автодополнением и проверкой типов. Разбираем, как настроить типизацию правильно.
TypeScript в Astro по умолчанию
Astro использует TypeScript внутри frontmatter (блок ---) и во всех .ts/.tsx-файлах. Файлы .astro — это TypeScript + HTML в одном флаконе.
---
// Полный 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
{
"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— максимально строгий
Типизация пропсов компонентов
---
// 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:
// 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 }; ---
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-переменных
// 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
// 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-роутах
// 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 });
}; Zod везде
Используйте Zod не только в Content Collections, но и для валидации форм, API-запросов и переменных окружения. Astro включает Zod нативно.
Strict mode
astro/tsconfigs/strict включает noUncheckedIndexedAccess — это защищает от ошибок
при работе с массивами (array[0] может быть undefined).
Пути через @
Настройте алиасы @components/*, @lib/* в tsconfig и astro.config. Избавит от
../../../components/Header.astro в импортах.
Проверка типов
# Проверить типы без сборки
npx astro check
# В CI/CD — выход с ошибкой при TS-ошибках
npx astro check && echo "Types OK" Добавьте в package.json:
{
"scripts": {
"check": "astro check",
"build": "astro check && astro build"
}
} Частые вопросы
Можно ли не использовать TypeScript в Astro?
Да, файлы .js и .jsx работают. Но VS Code и WebStorm дают автодополнение и подсказки только при TypeScript.
Как типизировать импорт изображений?
import myImage from '../assets/image.png';
// myImage — ImageMetadata { src, width, height, format } Как проверить тип пропсов в runtime? Используйте Zod внутри frontmatter:
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 и добавляйте типы постепенно.