I have been doing some new projects in React with Typescript, and I wanted to dump here the configuration I had been using. Usually, that type of boilerplate can either be generated by the npx command or established via trial and error.
Since it can be frustrating and dull, I tend to save the configuration, so I can easily refer to it later on if needed. A template would be ideal, but it’s also time-consuming to maintain and keep up to date. At least here you should have enough to get started. I’ll appreciate any templates or related configurations you have found that are better than this one, please share it in the comments below. 👌
Source Configuration
From react-scripts
If you don’t want to manually set it up, you can use the create-react-app command to generate a new project with
typescript.
Use the npx
command to create a new project with the following command:
npx create-react-app my-app --template typescript
This will set up the project using npm
and create a new working React project with typescript in the my-app
directory.
Else you can follow the next part of the article to set it up manually.
We will explain everything to do, to set up your project.
Setting up the project
Manually though, for the bare minimum, you will need the following dependencies.
Though to actually run the UI you will need something like babel to transpile it or use the template’s react-scripts
:
{
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"typescript": "^5.6.2"
}
}
Then in your tsconfig.json, it should be similar to any typescript project, minus the React specifics.
Use the following configuration, you may need to adjust it to your needs:
{
"compilerOptions": {
"baseUrl": ".",
"target": "es5",
"module": "esnext",
"moduleResolution": "node",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"jsx": "react",
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"noEmit": true,
"isolatedModules": true
},
"include": [
"**/*.ts",
"**/*.tsx",
"**/*.js"
],
"exclude": [
"node_modules"
]
}
- Note the
jsx
set toreact
to enable JSX syntax (You might usereact-jsx
too). - We also import the
dom
anddom.iterable
libraries to interact with the DOM since it’s a React project. - The
allowSyntheticDefaultImports
allows to import React modules asimport React from 'react'
instead ofimport * as React from 'react'
.
Some of it might be redundant or not necessary in your case
(e.g. you might not need to use resolveJsonModule
to import JSON data in your app, but it’s useful to know),
but it’s a working starting point that I have used. If you have a leaner or better one, let me know. 🤓
Using webpack with tsconfig.json
If you are using webpack
to bundle your project, and babel
to transpile it,
you will need to install these dependencies:
yarn add --dev html-webpack-plugin webpack webpack-cli webpack-dev-server
yarn add --dev @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript babel-loader
Now you can update the webpack.config.js
to include the following configuration.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.tsx',
mode: 'development',
module: {
rules: [
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'],
},
},
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
devServer: {
static: {
directory: path.join(__dirname, 'dist'),
},
compress: true,
port: 9000,
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
};
And now assuming the project is properly set up with a index.html
and a React index.tsx
file,
you can add commands to your package.json to run the project:
{
"main": "index.js",
"scripts": {
"start": "webpack serve --open",
"build": "webpack"
}
}
There are other alternatives to webpack
and babel
, but I have used this setup in the past and it works well.
If you know better, I am keen to be enlightened 💡 on the subject.
Using custom paths
You can set up custom paths in your tsconfig.json
to make it “easier” to import your files.
Though when changing the file’s directory, my IDE didn’t always update all the path accordingly.
I’ll leave the setup here as it is a nice to know feature.
First you need to set up the paths in the tsconfig.json
:
{
"compilerOptions": {
"paths": {
"@_components/*": [
"src/components/*"
],
"@_hooks/*": [
"src/hooks/*"
]
}
}
}
Then make sure you do the same for your webpack.config.js
, if you are using it (following the previous example).
In my case, I am creating two paths for the components and hooks:
module.exports = {
// ... other configs
resolve: {
extensions: ['.tsx', '.ts', '.js'],
alias: {
'@_hooks': path.resolve(__dirname, 'src/hooks'),
'@_components': path.resolve(__dirname, 'src/components'),
}
},
};
Nice! There’s a new alias for the components and hooks, everything following that path (src/components
and src/hooks
)
can be imported with the alias (e.g. @_components
and @_hooks
).
It also works with the subdirectories.
And for example, I can easily import my hook using:
import useMyHook from '@_hooks/useMyHook';
And that’s it! 🎉 The hook import path will be recognised within the IDE and the project will compile correctly. When using multiple subdirectories, the import path may become very long, so having this shorter path alias can reduce the clutter in the import statement.
Test configuration
Test setup in typescript
We have talked about configuring jest for a typescript project in a previous article, here it will be specifically for a React project, with the necessary dependencies and configuration.
First let’s install the dependencies:
yarn add --dev @testing-library/dom @testing-library/jest-dom @testing-library/react @types/jest jest jest-environment-jsdom ts-jest typescript
Now your package.json
should include those dependencies as well as the one previously installed in the source
configuration parts.
But those are the main ones needed for your test setup:
{
"devDependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/react": "^16.0.1",
"@types/jest": "^29.5.12",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"ts-jest": "^29.2.5",
"typescript": "^5.6.2"
}
}
Let’s continue for the jest configuration in the jest.config.js
file, though, you can also have it as a typescript
file,
it’s rather easy to convert:
module.exports = {
roots: ['<rootDir>/src'],
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
testRegex: '\\.(test|spec)\\.tsx$',
setupFilesAfterEnv: ['<rootDir>/setupTests.ts'],
testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules/'],
testEnvironment: 'jest-environment-jsdom',
collectCoverage: true,
coverageReporters: ['json', 'lcov', 'text', 'clover'],
moduleDirectories: ['node_modules', '<rootDir>/'],
};
In this configuration:
- the tests are expected within the
src
directory, so we use theroots
option to specify that. - It will use
ts-jest
to transform the typescript test files and run them. - It will run the tests matching the
testRegex
ending with.test.tsx
or.spec.tsx
. - The
setupTests.ts
file will be used to set up the test environment before running the tests. - It will also use the
jest-environment-jsdom
to run the tests in a browser-like environment (to interact with the DOM). - It will also collect coverage automatically
collectCoverage
set to true and report it in different formats with thecoverageReporters
option.
And now you should be ready to write some tests for your React components in typescript. Check out these articles for some testing help about static and interactive testing in React.
Final touches
Missing eslint? You can set up eslint following this article. Eslint is useful to consolidate your code style and enforce some rules in your project. It is not mandatory, but I find using it helps me keep the code clean and consistent.
With the source and test configuration set up, nothing should stop you now from building the best React app you have ever made! Until the next one. 🙃