10 TypeScript Tips for Better Astro Projects
TypeScript and Astro are a natural fit. Content Collections give you end-to-end type safety from your Markdown frontmatter to your components. Here are ten patterns that will make your Astro + TypeScript projects more maintainable and enjoyable.
1. Leverage Content Collection Schemas
Don’t settle for Record<string, unknown>. Define explicit schemas with Zod:
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
pubDate: z.coerce.date(),
draft: z.boolean().default(false),
tags: z.array(z.string()).default([]),
}),
});
This gives you autocomplete, validation at build time, and clear error messages when frontmatter is invalid.
2. Type Your Utility Functions
When you write helpers for formatting dates or computing reading time, add proper return types:
export function formatDate(date: Date, locale = 'en-US'): string {
return new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'long',
day: 'numeric',
}).format(date);
}
3. Use satisfies for Config Objects
For objects that need to match a certain shape but also preserve literal types:
const SITE = {
name: 'Hermes Prime',
url: 'https://example.com',
} as const;
4. Extract Reusable Types
When you have complex props, extract them:
export interface BlogPostProps {
post: CollectionEntry<'blog'>;
prev: CollectionEntry<'blog'> | null;
next: CollectionEntry<'blog'> | null;
}
5. Use Generic Components Sparingly
Astro components are mostly presentational. Keep generics for truly reusable logic; prefer composition for layout variations.
6. Type Your API Routes
If you add server endpoints, type the request and response:
export const GET = async ({ params }: { params: { id: string } }) => {
// params.id is string
return new Response(JSON.stringify({ id: params.id }));
};
7. Strict Mode Is Your Friend
Enable strict in tsconfig.json. It catches more bugs at compile time and encourages better patterns.
8. Use astro:content Types
Import CollectionEntry and RenderResult from astro:content instead of defining your own. They stay in sync with Astro’s internals.
9. Type Your Environment Variables
interface ImportMetaEnv {
readonly PUBLIC_API_URL: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
10. Document Complex Types
When a type is non-obvious, add a JSDoc comment. Future you will thank present you.
These tips should give you a solid foundation for type-safe Astro development. Combine them with good Content Collection schemas and you’ll rarely hit runtime type errors.