Skip to content

astro

TypeScript

Astro

TypeScript

TypeScript


This way, you avoid edge cases where Astro's bundler may try to incorrectly bundle your imported types as if they were JavaScript.

You can configure TypeScript to enforce type imports in your `tsconfig.json` file. Set [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax) to `true`. TypeScript will check your imports and tell you when `import type` should be used. This setting is enabled by default in all our presets.

```json title="tsconfig.json" ins={3}
{
  "compilerOptions": {
    "verbatimModuleSyntax": true
  }
}

Import Aliases

Astro supports import aliases that you define in your tsconfig.json paths configuration. Read our imports guide to learn more.

---


---
{
  "compilerOptions": {
    "paths": {
      "@components/*": ["./src/components/*"],
      "@layouts/*": ["./src/layouts/*"]
    }
  }
}

Extending global types

You can create src/env.d.ts as a convention for adding custom types declarations, or to benefit from Astro types if you don't have a tsconfig.json:

// Custom types declarations
declare var myString: string;

// Astro types, not necessary if you already have a `tsconfig.json`
/// <reference path="../.astro/types.d.ts" />

window and globalThis

You may want to add a property to the global object. You can do this by adding top-level declarations using the declare keyword to your env.d.ts file:

declare var myString: string;
declare function myFunction(): boolean;

This will provide typing to globalThis.myString and globalThis.myFunction, as well as window.myString and window.myFunction.

Note that window is only available in client-side code. globalThis is available both server-side and client-side, but its server-side value won't be shared with the client.

If you only want to type a property on the window object, provide a Window interface instead:

interface Window {
	myFunction(): boolean;
}

Add non-standard attributes

You may want to define a type for custom attributes or CSS properties. You can extend the default JSX definitions to add non-standard attributes by redeclaring the astroHTML.JSX namespace in a .d.ts file.

declare namespace astroHTML.JSX {
  interface HTMLAttributes {
    "data-count"?: number;
    "data-label"?: string;
  }

  // Add a CSS custom property to the style object
  interface CSSProperties {
    "--theme-color"?: "black" | "white";
  }
}

:::note astroHTML is injected globally inside .astro components. To use it in TypeScript files, use a triple-slash directive:

/// <reference types="astro/astro-jsx" />

type MyAttributes = astroHTML.JSX.ImgHTMLAttributes;

:::

Using imports

You may want to extend global types by reusing types declared elsewhere in your project or from an external library. To do this, use dynamic imports:

type Product = {
  id: string;
  name: string;
  price: number;
};

declare namespace App {
  interface Locals {
    orders: Map<string, Product[]>
    session: import("./lib/server/session").Session | null;
    user: import("my-external-library").User;
  }
}

A .d.ts file is an ambient module declaration. While its syntax is similar to ES modules, these files do not allow top-level imports/exports. If TypeScript encounters one, the file will be considered a module augmentation and this will break your global types.

Component Props

Astro supports typing your component props via TypeScript. To enable, add a TypeScript Props interface to your component frontmatter. An export statement may be used, but is not necessary. The Astro VS Code Extension will automatically look for the Props interface and give you proper TS support when you use that component inside another template.

---
interface Props {
  name: string;
  greeting?: string;
}

const { greeting = "Hello", name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>

Common prop type patterns

  • If your component takes no props or slotted content, you can use type Props = Record<string, never>.
  • If your component must be passed children to its default slot, you can enforce this by using type Props = { children: any; };.

Type Utilities

Astro comes with some built-in utility types for common prop type patterns. These are available under the astro/types entrypoint.

Built-in HTML attributes

Astro provides the HTMLAttributes type to check that your markup is using valid HTML attributes. You can use these types to help build component props.

For example, if you were building a <Link> component, you could do the following to mirror the default HTML attributes for <a> tags in your component’s prop types.

---

// use a `type`
type Props = HTMLAttributes<"a">;

// or extend with an `interface`
interface Props extends HTMLAttributes<"a"> {
  myProp?: boolean;
}

const { href, ...attrs } = Astro.props;
---
<a href={href} {...attrs}>
  <slot />
</a>

ComponentProps type

This type export allows you to reference the Props accepted by another component, even if that component doesn't export that Props type directly.

The following example shows using the ComponentProps utility from astro/types to reference a <Button /> component's Props types:

---


type ButtonProps = ComponentProps<typeof Button>;
---

Polymorphic type

Astro includes a helper to make it easier to build components that can render as different HTML elements with full type safety. This is useful for components like <Link> that can render as either <a> or <button> depending on the props passed to it.

The example below implements a fully-typed, polymorphic component that can render as any HTML element. The HTMLTag type is used to ensure that the as prop is a valid HTML element.

---

type Props<Tag extends HTMLTag> = Polymorphic<{ as: Tag }>;

const { as: Tag, ...props } = Astro.props;
---
<Tag {...props} />

Infer getStaticPaths() types

Astro includes helpers for working with the types returned by your getStaticPaths() function for dynamic routes.

You can get the type of Astro.params with InferGetStaticParamsType and the type of Astro.props with InferGetStaticPropsType or you can use GetStaticPaths to infer both at once:

---



  return posts.map((post) => {
    return {
      params: { id: post.id },
      props: { draft: post.data.draft, title: post.data.title },
    };
  });
}) satisfies GetStaticPaths;

type Params = InferGetStaticParamsType<typeof getStaticPaths>;
type Props = InferGetStaticPropsType<typeof getStaticPaths>;

const { id } = Astro.params;
//                   ^? { id: string; }

const { title } = Astro.props;
//                      ^? { draft: boolean; title: string; }
---

Type checking

To see type errors in your editor, please make sure that you have the Astro VS Code extension installed. Please note that the astro start and astro build commands will transpile the code with esbuild, but will not run any type checking. To prevent your code from building if it contains TypeScript errors, change your "build" script in package.json to the following:

{
  "scripts": {
    "build": "astro build",
    "build": "astro check && astro build",
  },
}

:::note astro check checks all the files included in your TypeScript project. To check types within Svelte and Vue files, you can use the svelte-check and the vue-tsc packages respectively. :::

import ReadMore from '~/components/ReadMore.astro'

Read more about .ts file imports in Astro.

Read more about TypeScript Configuration.

Troubleshooting

Errors typing multiple JSX frameworks at the same time

An issue may arise when using multiple JSX frameworks in the same project, as each framework requires different, sometimes conflicting, settings inside tsconfig.json.

Solution: Set the jsxImportSource setting to react (default), preact or solid-js depending on your most-used framework. Then, use a pragma comment inside any conflicting file from a different framework.

For the default setting of jsxImportSource: react, you would use:

// For Preact
/** @jsxImportSource preact */

// For Solid
/** @jsxImportSource solid-js */