# TypeScript

> Learn how to use Astro's built-in TypeScript support.

Astro ships with built-in support for [TypeScript](https://www.typescriptlang.org/). You can import `.ts` and `.tsx` files in your Astro project, write TypeScript code directly inside your [Astro component](/en/basics/astro-components/#the-component-script), and even use an [`astro.config.ts`](/en/guides/configuring-astro/#the-astro-config-file) file for your Astro configuration if you like.

Using TypeScript, you can prevent errors at runtime by defining the shapes of objects and components in your code. For example, if you use TypeScript to [type your component’s props](#component-props), you’ll get an error in your editor if you set a prop that your component doesn’t accept.

You don’t need to write TypeScript code in your Astro projects to benefit from it. Astro always treats your component code as TypeScript, and the [Astro VS Code Extension](/en/editor-setup/) will infer as much as it can to provide autocompletion, hints, and errors in your editor.

The Astro dev server won’t perform any type checking, but you can use a [separate script](#type-checking) to check for type errors from the command line.

## Setup

[Section titled “Setup”](#setup)

Astro starter projects include a `tsconfig.json` file in your project. Even if you don’t write TypeScript code, this file is important so that tools like Astro and VS Code know how to understand your project. Some features (like npm package imports) aren’t fully supported in the editor without a `tsconfig.json` file. If you install Astro manually, be sure to create this file yourself.

### TSConfig templates

[Section titled “TSConfig templates”](#tsconfig-templates)

Three extensible `tsconfig.json` templates are included in Astro: `base`, `strict`, and `strictest`. The `base` template enables support for modern JavaScript features and is also used as a basis for the other templates. We recommend using `strict` or `strictest` if you plan to write TypeScript in your project. You can view and compare the three template configurations at [astro/tsconfigs/](https://github.com/withastro/astro/blob/main/packages/astro/tsconfigs/).

To inherit from one of the templates, use [the `extends` setting](https://www.typescriptlang.org/tsconfig#extends):

tsconfig.json

```json
{
  "extends": "astro/tsconfigs/base"
}
```

Additionally, we recommend setting `include` and `exclude` as follows to benefit from Astro types and avoid checking built files:

tsconfig.json

```diff
{
  "extends": "astro/tsconfigs/base",
  +"include": [".astro/types.d.ts", "**/*"],
  +"exclude": ["dist"]
}
```

### TypeScript editor plugin

[Section titled “TypeScript editor plugin”](#typescript-editor-plugin)

The [Astro TypeScript plugin](https://www.npmjs.com/package/@astrojs/ts-plugin) can be installed separately when you are not using the [official Astro VS Code extension](https://marketplace.visualstudio.com/items?itemName=astro-build.astro-vscode). This plugin is automatically installed and configured by the VS Code extension, and you do not need to install both.

This plugin runs only in the editor. When running `tsc` in the terminal, `.astro` files are ignored entirely. Instead, you can use [the `astro check` CLI command](/en/reference/cli-reference/#astro-check) to check both `.astro` and `.ts` files.

This plugin also supports importing `.astro` files from `.ts` files (which can be useful for re-exporting).

* npm

  ```shell
  npm install @astrojs/ts-plugin
  ```

* pnpm

  ```shell
  pnpm add @astrojs/ts-plugin
  ```

* Yarn

  ```shell
  yarn add @astrojs/ts-plugin
  ```

Then, add the following to your `tsconfig.json`:

tsconfig.json

```json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "@astrojs/ts-plugin"
      },
    ],
  }
}
```

To check that the plugin is working, create a `.ts` file and import an Astro component into it. You should have no warning messages from your editor.

### UI Frameworks

[Section titled “UI Frameworks”](#ui-frameworks)

If your project uses a [UI framework](/en/guides/framework-components/), additional settings depending on the framework might be needed. Please see your framework’s TypeScript documentation for more information. ([Vue](https://vuejs.org/guide/typescript/overview.html#using-vue-with-typescript), [React](https://react-typescript-cheatsheet.netlify.app/docs/basic/setup), [Preact](https://preactjs.com/guide/v10/typescript), [Solid](https://www.solidjs.com/guides/typescript), [Svelte](https://svelte.dev/docs/svelte/typescript))

## Type Imports

[Section titled “Type Imports”](#type-imports)

Use explicit type imports and exports whenever possible.

```diff
-import { SomeType } from "./script";
+import type { SomeType } from "./script";
```

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.

tsconfig.json

```diff
{
  "compilerOptions": {
    +"verbatimModuleSyntax": true
  }
}
```

## Import Aliases

[Section titled “Import Aliases”](#import-aliases)

Astro supports import aliases that you define in your `tsconfig.json` `paths` configuration. [Read our imports guide](/en/guides/imports/#aliases) to learn more.

src/pages/about/nate.astro

```astro
---
import HelloWorld from "@components/HelloWorld.astro";
import Layout from "@layouts/Layout.astro";
---
```

tsconfig.json

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

## Extending global types

[Section titled “Extending global types”](#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`:

src/env.d.ts

```ts
// 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`

[Section titled “window and globalThis”](#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:

src/env.d.ts

```ts
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:

src/env.d.ts

```ts
interface Window {
  myFunction(): boolean;
}
```

### Add non-standard attributes

[Section titled “Add non-standard attributes”](#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.

src/env.d.ts

```ts
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](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html):

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


type MyAttributes = astroHTML.JSX.ImgHTMLAttributes;
```

### Using imports

[Section titled “Using imports”](#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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import):

src/env.d.ts

```ts
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](https://www.typescriptlang.org/docs/handbook/modules/reference.html#ambient-modules) 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](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) and this will break your global types.

## Component Props

[Section titled “Component Props”](#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](/en/editor-setup/) will automatically look for the `Props` interface and give you proper TS support when you use that component inside another template.

src/components/HelloProps.astro

```diff
---
+interface Props {
+  name: string;
+  greeting?: string;
+}


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

### Common prop type patterns

[Section titled “Common prop type patterns”](#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

[Section titled “Type Utilities”](#type-utilities)

**Added in:** `astro@1.6.0`

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

[Section titled “Built-in HTML attributes”](#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.

src/components/Link.astro

```astro
---
import type { HTMLAttributes } from "astro/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

[Section titled “ComponentProps type”](#componentprops-type)

**Added in:** `astro@4.3.0`

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:

src/pages/index.astro

```astro
---
import type { ComponentProps } from "astro/types";
import Button from "./Button.astro";


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

### Polymorphic type

[Section titled “Polymorphic type”](#polymorphic-type)

**Added in:** `astro@2.5.0`

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`](#built-in-html-attributes) type is used to ensure that the `as` prop is a valid HTML element.

```astro
---
import type { HTMLTag, Polymorphic } from "astro/types";


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


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

### Infer `getStaticPaths()` types

[Section titled “Infer getStaticPaths() types”](#infer-getstaticpaths-types)

**Added in:** `astro@2.1.0`

Astro includes helpers for working with the types returned by your [`getStaticPaths()`](/en/reference/routing-reference/#getstaticpaths) function for dynamic routes.

You can get the type of [`Astro.params`](/en/reference/api-reference/#params) with `InferGetStaticParamsType` and the type of [`Astro.props`](/en/reference/api-reference/#props) with `InferGetStaticPropsType` or you can use `GetStaticPaths` to infer both at once:

src/pages/posts/\[...id].astro

```astro
---
import type {
  InferGetStaticParamsType,
  InferGetStaticPropsType,
  GetStaticPaths,
} from "astro";


export const getStaticPaths = (async () => {
  const posts = await getCollection("blog");
  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 as Params;
//                   ^? { id: string; }


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

## Type checking

[Section titled “Type checking”](#type-checking)

To see type errors in your editor, please make sure that you have the [Astro VS Code extension](/en/editor-setup/) 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:

package.json

```diff
{
  "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`](https://www.npmjs.com/package/svelte-check) and the [`vue-tsc`](https://www.npmjs.com/package/vue-tsc) packages respectively.

Read more about [`.ts` file imports](/en/guides/imports/#typescript) in Astro.

Read more about [TypeScript Configuration](https://www.typescriptlang.org/tsconfig/).

## Troubleshooting

[Section titled “Troubleshooting”](#troubleshooting)

### Errors typing multiple JSX frameworks at the same time

[Section titled “Errors typing multiple JSX frameworks at the same time”](#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](https://www.typescriptlang.org/tsconfig#jsxImportSource) to `react` (default), `preact` or `solid-js` depending on your most-used framework. Then, use a [pragma comment](https://www.typescriptlang.org/docs/handbook/jsx.html#configuring-jsx) inside any conflicting file from a different framework.

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

```jsx
// For Preact
/** @jsxImportSource preact */


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