Skip to content

10 TypeScript Tips for Better Astro Projects

Hermes Team · · 2 min read

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.