26. TypeScript в Astro
Astro поддерживает TypeScript «из коробки» — не нужно устанавливать дополнительные пакеты или настраивать Babel. Весь TypeScript компилируется при сборке, а в режиме разработки вы получаете полноценное автодополнение и проверку типов.
Конфигурация tsconfig.json
Заголовок раздела «Конфигурация tsconfig.json»Astro генерирует оптимальный tsconfig.json при создании проекта. Рекомендуется использовать один из официальных пресетов:
{ "extends": "astro/tsconfigs/strict", "compilerOptions": { "baseUrl": ".", "paths": { "@components/*": ["src/components/*"], "@layouts/*": ["src/layouts/*"], "@utils/*": ["src/utils/*"] } }}Пресеты строгости: base, strict, strictest. Для новых проектов рекомендуется strict — он включает все полезные проверки без излишней строгости.
Типизация пропсов через interface Props
Заголовок раздела «Типизация пропсов через interface Props»Ключевая конвенция Astro: экспортируйте интерфейс Props прямо в frontmatter компонента. Astro автоматически его подхватывает:
---export interface Props { title: string; description: string; image?: string; // опциональный variant: 'primary' | 'secondary'; // union type tags: string[]; meta?: { author: string; date: Date; };}
const { title, description, image, variant = 'primary', tags, meta,} = Astro.props;---
<article class={`card card--${variant}`}> {image && <img src={image} alt={title} />} <h2>{title}</h2> <p>{description}</p> {meta && <span>{meta.author} · {meta.date.toLocaleDateString('ru')}</span>} <div class="tags"> {tags.map(tag => <span class="tag">{tag}</span>)} </div></article>При использовании компонента TypeScript будет проверять все пропсы:
<!-- Ошибка: variant — обязательный, теги должны быть массивом --><Card title="Привет" description="Текст" variant="primary" tags={['astro', 'ts']} />Типизация getStaticPaths
Заголовок раздела «Типизация getStaticPaths»Функция getStaticPaths возвращает пути для статической генерации. Используйте тип GetStaticPaths для корректной типизации:
---import type { GetStaticPaths } from 'astro';import { getCollection } from 'astro:content';
export const getStaticPaths: GetStaticPaths = async () => { const posts = await getCollection('blog'); return posts.map(post => ({ params: { slug: post.slug }, props: { post }, }));};
// Типизация пропсов страницыinterface Props { post: Awaited<ReturnType<typeof getCollection<'blog'>>>[number];}
const { post } = Astro.props;---CollectionEntry<T> для контент-коллекций
Заголовок раздела «CollectionEntry<T> для контент-коллекций»При работе с Content Collections используйте тип CollectionEntry:
---import type { CollectionEntry } from 'astro:content';
interface Props { post: CollectionEntry<'blog'>;}
const { post } = Astro.props;const { title, description, publishedAt } = post.data;---Тип CollectionEntry<'blog'> автоматически выводится из вашей схемы коллекции, поэтому post.data будет полностью типизирован.
Типы Astro
Заголовок раздела «Типы Astro»Пространство имён astro предоставляет дополнительные утилитарные типы:
import type { AstroComponentFactory, // Тип Astro-компонента HTMLAttributes, // HTML атрибуты с aria- и data- MarkdownInstance, // Импортированный .md файл ImageMetadata, // Импортированное изображение AstroGlobal, // Тип Astro (глобальный объект)} from 'astro';
// Расширение HTML атрибутовinterface ButtonProps extends HTMLAttributes<'button'> { variant: 'primary' | 'danger'; loading?: boolean;}
// Передача компонента как пропсаinterface LayoutProps { header: AstroComponentFactory; footer: AstroComponentFactory;}Строгая типизация в API-роутах
Заголовок раздела «Строгая типизация в API-роутах»import type { APIRoute } from 'astro';
interface PostBody { title: string; content: string;}
export const POST: APIRoute = async ({ request }) => { const body = await request.json() as PostBody;
if (!body.title || !body.content) { return new Response(JSON.stringify({ error: 'Missing fields' }), { status: 400, headers: { 'Content-Type': 'application/json' }, }); }
return new Response(JSON.stringify({ success: true }), { headers: { 'Content-Type': 'application/json' }, });};