Here’s a rewritten version of the article, preserving the original ideas while improving clarity, structure, and flow:

Crafting a Better Developer Experience in Astro with TypeScript

One of the things I love most about Astro is its emphasis on developer experience (DX), especially for onboarding new team members. While Astro provides a solid foundation out of the box, it’s still possible to build a complex system that becomes difficult for others (or even future-you) to navigate. That’s something I actively want to avoid.

When working with multiple developers, consistency is key. I want everyone to know exactly what to expect from each component. Ideally, developers should be able to use a component without having to dig through its source code just to understand how it works. Even better, the system should guide them toward best practices and prevent common mistakes.

That’s where TypeScript comes in. Astro ships with TypeScript support by default, and while it’s optional, using it can significantly improve your DX. Let’s walk through how you can use TypeScript to build more intuitive, reliable components in Astro.

Watch the Video

Prefer video? I’ve also created a video walkthrough of this article. You can watch it on YouTube (with chapters and captions) here.

Getting Started

To follow along, start by creating a new Astro project using the minimal template:

npm create astro@latest

Once you’ve got your project set up, remove the default component from the index route to start with a clean slate.

For styling, I recommend adding Tailwind CSS:

npx astro add tailwind

With that, you’re ready to build your first component.

Building a Reusable Heading Component

Let’s create a flexible component that supports all HTML heading levels (h1–h6), allows custom font sizes and weights, and accepts any additional HTML attributes.

Step 1: Dynamic HTML Tags

Create a new component at ./src/components/Heading.astro:


// ./src/components/Heading.astro
const { as } = Astro.props;
const As = as;



Astro requires dynamic components to start with a capital letter, so we alias the as prop to As. This allows us to dynamically render any HTML tag.

Now, use the component in your index route:


// ./src/pages/index.astro
import Layout from ‘../layouts/Layout.astro’;
import Heading from ‘../components/Heading.astro’;


Hello!Hello world

Step 2: Adding Font Size and Weight

Let’s make the component more customizable by adding support for font size and weight. We’ll also set default values and use Tailwind CSS classes.

Update Heading.astro:


const weights = {
bold: “font-bold”,
semibold: “font-semibold”,
medium: “font-medium”,
light: “font-light”
};

const sizes = {
“6xl”: “text-6xl”,
“5xl”: “text-5xl”,
“4xl”: “text-4xl”,
“3xl”: “text-3xl”,
“2xl”: “text-2xl”,
xl: “text-xl”,
lg: “text-lg”,
md: “text-md”,
sm: “text-sm”
};

const { as: As = “h2”, weight = “medium”, size = “2xl” } = Astro.props;



Now you can use the component like this:

Hello!Hello worldStep 3: Supporting Additional HTML Attributes

To make the component more flexible, we should allow developers to pass in any valid HTML attribute.

Update the props destructuring to capture the rest of the props:


const { as: As = “h2”, weight = “medium”, size = “md”, …attrs } = Astro.props;

Then spread those attributes onto the element:



This allows developers to pass attributes like id or class directly:

Hello!Hello worldAstro will automatically merge any additional classes with those from class:list—no extra work needed!

Step 4: Adding TypeScript for Safer DX

At this point, the component works great, but

Similar Posts