Components and layouts

Type component props

Declare the component contract with a Props interface and provide defaults for optional values.

In the previous lesson props were an informal agreement. Nothing stopped a parent from forgetting title, or passing a string where the component wanted a boolean. TypeScript turns that agreement into a contract the editor checks for you.

The mechanism is one interface with a reserved name. Declare interface Props in the component script and Astro applies it to Astro.props:

---
interface Props {
  title: string
  featured?: boolean
}

const { title, featured = false } = Astro.props
---

<article class:list={{ featured }}>
  <h2>{title}</h2>
</article>

The name matters. Call it Props and every place you use the component gets checked too. Hover a <Card> tag in the editor and you see exactly what it accepts.

Now <Card featured="yes" /> is an error, because a quoted attribute is a string and featured wants a boolean. Forgetting title is an error too:

Property 'title' is missing in type '{ featured: true; }' but required in type 'Props'.

Optional props and defaults

Mark optional props with ?. Put the default in the destructuring, right next to the type:

---
interface Props {
  title: string
  count?: number
}

const { title, count = 0 } = Astro.props
---

Keep the two consistent. If you declare count?: number and then default it to '0', the type says number and the value is a string. Every component downstream inherits that confusion. My advice is to always read the interface and the destructuring as one pair.

Where the errors show up

In the editor as you type, and when you run the checker:

npx astro check

astro check needs the @astrojs/check package, and the first run offers to install it. I run it before every commit, because a plain build does not type check and will happily ship a wrong prop.

What Props does not do

The interface disappears from the compiled output. It is not runtime validation.

If a value comes from a URL, a form, a CMS, or an external API, TypeScript can’t know what arrives at runtime. Validate that input before you pass it to the component. Content collection schemas, which we cover later in this course, do exactly that for Markdown frontmatter.

Think of Props as a contract between your own files. It stops you from misusing your own components. It cannot make untrusted data truthful.

Try this on your project: add a Props interface to a component you already have, then break one call site on purpose with the wrong type. The editor should flag the page that uses the component, not just the component file.

Lesson completed