Astro types come from three places: astro (core types like APIRoute, GetStaticPaths and ImageMetadata), astro/types (component helpers like HTMLAttributes, Polymorphic and ComponentProps), and astro:content (CollectionEntry and friends). This cheatsheet lists the ones you’ll actually use, where to import each from, and a short example. Run npx astro check to type-check .astro files.
Key Takeaways
- Declare
interface Propsin a component and Astro typesAstro.propsautomatically.HTMLAttributes<'a'>lets a wrapper accept every attribute of the element it renders.CollectionEntry<'blog'>types a content entry;GetStaticPathsplussatisfiestypes routes.- Extend
App.Localsinsrc/env.d.tsto type middleware data.
Component props
---
interface Props {
title: string;
href?: string;
size?: 'sm' | 'md' | 'lg';
}
const { title, href, size = 'md' } = Astro.props;
---
type Props = { ... } works too. Astro reads either.
Wrapping HTML elements
---
import type { HTMLAttributes } from 'astro/types';
interface Props extends HTMLAttributes<'button'> {
variant?: 'primary' | 'ghost';
}
const { variant = 'primary', ...attrs } = Astro.props;
---
<button class={`btn btn-${variant}`} {...attrs}><slot /></button>
Polymorphic components
---
import type { HTMLTag, Polymorphic } from 'astro/types';
type Props<Tag extends HTMLTag> = Polymorphic<{ as: Tag }>;
const { as: Tag = 'div', ...props } = Astro.props;
---
<Tag {...props}><slot /></Tag>
<Box as="a" href="/"> is type-checked against <a> attributes.
Reusing another component’s props
import type { ComponentProps } from 'astro/types';
import Button from './Button.astro';
type ButtonProps = ComponentProps<typeof Button>;
Content collections
import type { CollectionEntry, CollectionKey } from 'astro:content';
type Post = CollectionEntry<'blog'>;
type Data = CollectionEntry<'blog'>['data'];
function sortByDate(posts: Post[]) {
return posts.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
}
Routes
import type { GetStaticPaths, InferGetStaticPropsType, InferGetStaticParamsType } from 'astro';
export const getStaticPaths = (async () => {
const posts = await getCollection('blog');
return posts.map((post) => ({ params: { slug: post.id }, props: { post } }));
}) satisfies GetStaticPaths;
type Props = InferGetStaticPropsType<typeof getStaticPaths>;
type Params = InferGetStaticParamsType<typeof getStaticPaths>;
const { post } = Astro.props as Props;
Pagination
import type { Page } from 'astro';
interface Props { page: Page<CollectionEntry<'blog'>> }
Endpoints, middleware and context
import type { APIRoute, APIContext, MiddlewareHandler } from 'astro';
export const GET: APIRoute = ({ params, url }) => Response.json({ id: params.id });
export async function POST(context: APIContext) {
return new Response(null, { status: 204 });
}
Middleware is usually typed through defineMiddleware() from astro:middleware, which infers the handler type.
Images
import type { ImageMetadata } from 'astro';
const images = import.meta.glob<{ default: ImageMetadata }>('../assets/*.jpg', { eager: true });
GetImageResult types the return value of getImage().
Markdown
import type { MarkdownHeading } from 'astro';
interface Props { headings: MarkdownHeading[] } // { depth, slug, text }
Locals and sessions
// src/env.d.ts
declare namespace App {
interface Locals {
user: { id: string; name: string } | null;
}
interface SessionData {
cart: string[];
}
}
Astro.locals.user and Astro.session?.get('cart') are now typed.
Environment variables
astro:env modules are typed from env.schema automatically after npx astro sync. No manual declarations needed.
tsconfig
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
Presets: base, strict, strictest. strict is a good default for new projects.
Checking types
npx astro check # type-check .astro, .ts and framework files
npx astro sync # regenerate generated types
Add astro check to CI before the build. See the Astro CLI cheatsheet for both commands, the Astro components guide for props in practice, and the content collections cheatsheet for collection APIs. The TypeScript guide covers setup.
FAQ
Does Astro type-check during the build?
No. astro build doesn’t run the type checker. Run astro check separately, for example in CI.
Where do the generated types live?
In .astro/types.d.ts, generated by astro sync and the dev server. Include it in tsconfig.json.