xref: /expo/docs/pages/guides/typescript.mdx (revision f3451625)
1---
2title: Use TypeScript
3description: An in-depth guide on configuring an Expo project with TypeScript.
4---
5
6import { Terminal } from '~/ui/components/Snippet';
7import { BoxLink } from '~/ui/components/BoxLink';
8import { GithubIcon } from '@expo/styleguide-icons';
9import { Tabs, Tab, TabsGroup } from '~/ui/components/Tabs';
10
11Expo has first-class support for [TypeScript](https://www.typescriptlang.org/). The JavaScript interface of the Expo SDK is completely written in TypeScript.
12
13<BoxLink
14  title="with-typescript"
15  description="See the example project on GitHub."
16  href="https://github.com/expo/examples/tree/master/with-typescript"
17  Icon={GithubIcon}
18/>
19
20<TabsGroup>
21
22## Get started
23
24### Quick start with a template
25
26The easiest way to get started is to initialize your new project using a TypeScript template:
27
28<Terminal cmd={['$ npx create-expo-app -t expo-template-blank-typescript']} />
29
30For npm, add the following `script` to the **package.json**:
31
32{/* prettier-ignore */}
33```json package.json
34{
35  "scripts": {
36    "ts:check": "tsc"
37    /* @hide ... */ /* @end */
38  }
39}
40```
41
42Then, to type-check the project, run the following command:
43
44<Tabs>
45<Tab label="npm">
46
47<Terminal cmd={['$ npm run ts:check']} />
48
49</Tab>
50
51<Tab label="yarn">
52
53<Terminal cmd={['$ yarn tsc']} />
54
55</Tab>
56</Tabs>
57
58When you create new source files in your project you should use the **.ts** extension or the **.tsx** if the file includes React components.
59
60### In an existing project
61
62Rename files to convert them to TypeScript. For example, rename **App.js** to **App.tsx**. Use the **.tsx** extension if the file includes React components (JSX). If the file does not include any JSX, you can use the **.ts** file extension.
63
64<Terminal cmd={['$ mv App.js App.tsx']} />
65
66> **For SDK 48 and higher**, running `npx expo start` prompts you to install the required dependencies, such as `typescript` and `@types/react`. **For SDK 47 and below**, the command also prompts you to install `@types/react-native` as an additional dependency.
67
68For npm, add the following `script` to the **package.json**:
69
70{/* prettier-ignore */}
71```json package.json
72{
73  "scripts": {
74    "ts:check": "tsc"
75    /* @hide ... */ /* @end */
76  }
77}
78```
79
80You can now run `npm run ts:check` or `yarn tsc` to type-check the project.
81
82## Base configuration
83
84> You can disable the TypeScript setup in Expo CLI with the environment variable `EXPO_NO_TYPESCRIPT_SETUP=1`
85
86A project's **tsconfig.json** should extend the `expo/tsconfig.base` by default. This sets the following default [compiler options](https://www.typescriptlang.org/docs/handbook/compiler-options.html) (which can be overwritten in your project's **tsconfig.json**):
87
88You can automatically generate a **tsconfig.json** file by running the command:
89
90<Terminal cmd={['$ npx expo customize tsconfig.json']} />
91
92## Project configuration
93
94Expo CLI will automatically modify your **tsconfig.json** to the preferred default which is optimized for universal React development:
95
96```json tsconfig.json
97{
98  "extends": "expo/tsconfig.base",
99  "compilerOptions": {},
100  "include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
101}
102```
103
104The default configuration for TypeScript is user-friendly and encourages adoption. However, if you prefer strict type checking, you can enable it by adding `"strict": true` to the `compilerOptions`. We recommend enabling this to minimize the chance of introducing runtime errors.
105
106Some language features may require additional configuration. For example, if want to use decorators you'll need to add the `experimentalDecorators` option. For more information on the available properties see the [TypeScript compiler options](https://www.typescriptlang.org/docs/handbook/compiler-options.html) documentation.
107
108## Path aliases
109
110Expo CLI supports [path aliases](https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping) in your project's **tsconfig.json** automatically. This enables you to import modules using a custom alias instead of a relative path.
111
112For example, if you have a file at **src/components/Button.tsx** and wish to import it using the alias **@/components/Button** as follows:
113
114```tsx
115import Button from '@/components/Button';
116```
117
118Then simply add the alias **@/\*** in the project's **tsconfig.json** and set it to the **src** directory:
119
120```json tsconfig.json
121{
122  "compilerOptions": {
123    "baseUrl": ".",
124    "paths": {
125      "@/*": ["src/*"]
126    }
127  }
128}
129```
130
131Consider the following when using path aliases:
132
133- Restart Expo CLI after changing **tsconfig.json** to update path aliases. You don't need to clear the Metro cache when the aliases change.
134- If not using TypeScript, **jsconfig.json** can serve as an alternative to **tsconfig.json**.
135- Path aliases add additional resolution time when defined.
136- Path aliases are only supported by Metro (including Metro web) and not by `@expo/webpack-config`.
137- Bare projects require additional setup for this feature. See the [versioned Metro setup guide](/versions/latest/config/metro#bare-workflow-setup) for more information.
138
139<Tabs>
140
141<Tab label="SDK 50 and above">
142
143`tsconfigPaths` is enabled by default. You can disable it by setting `tsconfigPaths` to `false` in the project's [app config](/workflow/configuration/):
144
145```json app.json
146{
147  "expo": {
148    "experiments": {
149      "tsconfigPaths": false
150    }
151  }
152}
153```
154
155</Tab>
156
157<Tab label="SDK 49">
158
159Set `tsconfigPaths` to `true` to enable path aliases in the project's [app config](/workflow/configuration/):
160
161```json app.json
162{
163  "expo": {
164    "experiments": {
165      "tsconfigPaths": true
166    }
167  }
168}
169```
170
171</Tab>
172
173</Tabs>
174
175## Absolute imports
176
177> Available in SDK 49 and higher.
178
179In SDK 49 projects, you'll need to enable absolute imports in the project's [app config](/workflow/configuration/):
180
181```json app.json
182{
183  "expo": {
184    "experiments": {
185      "tsconfigPaths": true
186    }
187  }
188}
189```
190
191Absolute imports from the project root directory are enabled automatically when the project contains a **tsconfig.json** or **jsconfig.json** file. For example:
192
193```tsx
194import Button from 'src/components/Button';
195// Imports `<project root>/src/components/Button`
196```
197
198You can modify the base directory in the tsconfig.json (or jsconfig.json) using the [baseUrl](https://www.typescriptlang.org/docs/handbook/module-resolution.html#base-url) option:
199
200```json tsconfig.json
201{
202  "compilerOptions": {
203    "baseUrl": "src"
204  }
205}
206```
207
208Consider the following when using absolute imports:
209
210- [`compilerOptions.baseUrl`](https://www.typescriptlang.org/docs/handbook/module-resolution.html#base-url) is automatically set to `.` when the `tsconfig.json` or **jsconfig.json** file exists.
211- Absolute imports in Node modules cannot be overwritten by absolute imports, as they take precedence.
212- Restarting Expo CLI is necessary to update [`compilerOptions.baseUrl`](https://www.typescriptlang.org/docs/handbook/module-resolution.html#base-url) after modifying **the tsconfig.json**.
213- If not using TypeScript, **jsconfig.json** can serve as an alternative to **tsconfig.json**.
214- Absolute imports are only supported by Metro (including Metro web) and not by `@expo/webpack-config`.
215- Bare projects require additional setup for this feature. See the [versioned Metro setup guide](/versions/latest/config/metro#bare-workflow-setup) for more information.
216
217## Type generation
218
219Some Expo libraries provide both static types and type generation capabilities. These types are automatically generated when the project builds or by running the `npx expo customize tsconfig.json` command.
220
221## TypeScript for config files
222
223If you want to use TypeScript for configuration files such as **webpack.config.js**, **metro.config.js**, or **app.config.js**, additional setup is needed. You can utilize the [`ts-node` require hook](https://github.com/TypeStrong/ts-node#programmatic) to import TypeScript files within your JS config file, allowing TypeScript imports while keeping the root file as JavaScript.
224
225<Tabs>
226<Tab label="npm">
227
228<Terminal cmd={['$ npm install ts-node typescript --save-dev']} />
229
230</Tab>
231
232<Tab label="yarn">
233
234<Terminal cmd={['$ yarn add -D ts-node typescript']} />
235
236</Tab>
237</Tabs>
238
239### webpack.config.js
240
241> Install the `@expo/webpack-config` package.
242
243```js webpack.config.js
244require('ts-node/register');
245module.exports = require('./webpack.config.ts');
246```
247
248```ts webpack.config.ts
249import createExpoWebpackConfigAsync from '@expo/webpack-config/webpack';
250import { Arguments, Environment } from '@expo/webpack-config/webpack/types';
251
252module.exports = async function (env: Environment, argv: Arguments) {
253  const config = await createExpoWebpackConfigAsync(env, argv);
254  // Customize the config before returning it.
255  return config;
256};
257```
258
259### metro.config.js
260
261```js metro.config.js
262require('ts-node/register');
263module.exports = require('./metro.config.ts');
264```
265
266```ts metro.config.ts
267import { getDefaultConfig } from 'expo/metro-config';
268
269const config = getDefaultConfig(__dirname);
270
271module.exports = config;
272```
273
274### app.config.js
275
276**app.config.ts** is supported by default. However, it doesn't support external TypeScript modules, or **tsconfig.json** customization. You can use the following approach to get a more comprehensive TypeScript setup:
277
278```js app.config.js
279require('ts-node/register');
280module.exports = require('./app.config.ts');
281```
282
283```ts app.config.ts
284import { ExpoConfig } from 'expo/config';
285
286// In SDK 46 and lower, use the following import instead:
287// import { ExpoConfig } from '@expo/config-types';
288
289const config: ExpoConfig = {
290  name: 'my-app',
291  slug: 'my-app',
292};
293
294export default config;
295```
296
297## Learn how to use TypeScript
298
299A good place to start learning TypeScript is the official [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html).
300
301**For TypeScript and React components,** we recommend referring to the [React TypeScript CheatSheet](https://github.com/typescript-cheatsheets/react) to learn how to type your React components in a variety of common situations.
302
303</TabsGroup>
304