Search⌘ K
AI Features

TypeScript Integration

Explore how to integrate TypeScript in a Next.js project by configuring tsconfig.json and managing dependencies. Understand customizing Babel to enable modern and experimental JavaScript features and configuring webpack for advanced bundling needs. Gain practical knowledge of tweaking next.config.js for tailored setups.

TypeScript configuration in Next.js

The Next.js source code is written in TypeScript and natively provides high-quality type definitions to make our developer experience even better. Configuring TypeScript as the default language for our Next.js app is very easy; we just have to create a TypeScript configuration file (tsconfig.json) inside the root of our project. If we try to run, we’ll see the following output:

It looks like you're trying to use TypeScript but do not have
the required package(s) installed.
Please install typescript and @types/react by running:
npm install --save typescript @types/react
If you are are not trying to use TypeScript, please remove
the tsconfig.json file from your package root (and any
TypeScript files in your pages directory).

As we can see, Next.js has correctly detected that we’re trying to use TypeScript and asks us to install all the required dependencies for using it as the primary language for our project. So now we just have to convert our JavaScript files to TypeScript, and we’re ready to go.

We may notice that even if we created an empty tsconfig.json file, after installing the required dependencies and rerunning the project, Next.js fills it with its default configurations. Of course, we can always customize the TypeScript options inside that file, but keep in mind that Next.js uses Babel to handle TypeScript files (via the @babel/plugin-transform-typescript), and it has some caveats, including the following:

  • The @babel/plugin-transform-typescript plu-gin does not support const enum, often used in TypeScript. To support it, make sure to add babel-plugin-const-enum to the Babel configuration.

  • Neither export = nor import = are supported because they can't be compiled to valid ECMAScriptThis is a JavaScript standard that's intended to ensure the interoperability of web pages across different web browsers. code. We should either install babel-plugin-replace-ts-export-assignment or convert our imports and exports to valid ECMAScript directives, such as import x, {y} from 'some-package' and export default x.

There are other caveats too. We suggest you read them before going further with using TypeScript as the main language for developing our Next.js app. Also, some compiler options might be a bit different from the default TypeScript ones; once again, we suggest you read the official Babel documentation, which will always be up to date.

Next.js also creates a next-env.d.ts file inside the root of our project. Feel free to edit it if you need to, but make sure not to delete it.

Custom Babel and webpack configuration

As already mentioned in the section above, we can customize Babel and webpack configurations. There might be many reasons we would like to customize our Babel configuration. If you’re not very familiar with it, let’s quickly explain what we’re talking about. Babel is a JavaScript transcompiler mainly used for transforming modern JavaScript code into a backward-compatible script, which will run without a problem on any browser.

If we’re writing a web app that must support older browsers such as Internet Explorer (IE) 10 or Internet Explorer 11, Babel will help us a lot. It allows us to use modern ES6/ESNextES6, also known as ECMAScript 2015, is a significant update to JavaScript that includes new features like arrow functions, promises, and classes to enhance web development. features and will transform them into IE-compatibleIE compatible code refers to the programming code that has been written in such a way that it can be properly executed or displayed by Internet Explorer (IE). code at build time, letting us maintain a beautiful developer experience with very few compromises.

Also, the JavaScript language (standardized under the ECMAScript specification) is quickly evolving. So while some fantastic features have already been announced, we’ll have to wait for years before being able to use them in both browsers and Node.js environments. That’s because after the ECMA committee has accepted these features, the companies developing web browsers and communities working on the Node.js project will have to plan a roadmap for adding support for these enhancements. Babel solves this problem by transpiling modern code into a compatible script for today’s environments.

For example, we may be familiar with this code:

export default function() {
console.log("Hello, World!");
};
Simple JavaScript function

But if we try to run it in Node.js, it will throw a syntax error because the JavaScript engine won’t recognize the export default keywords.

Babel will transform the preceding code into this equivalent ECMAScript code, at least until Node.js gets support for the export default syntax:

Javascript (babel-node)
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = _default;
function _default() {
console.log("Hello, World!");
}

This makes it possible to run this code on Node.js with no problems.

We can customize our default Next.js Babel configuration by simply creating a new file called .babelrc inside the root of our project. If we leave it empty, the Next.js build/development process will throw an error, so make sure to add at least the following code:

{
"presets": ["next/babel"]
}
Babel preset

This is the Babel preset created by the Vercel team specifically for building and developing Next.js applications. Let’s say that we’re building an application, and we want to use an experimental ECMAScript feature, such as the pipeline operator; if we’re not familiar with it, it basically allows us to rewrite this code as follows:

Javascript (babel-node)
console.log(Math.random() * 10);
// written using the pipeline operator becomes:
Math.random()
|> (x => x * 10)
|> console.log;

The pipeline operator has not been officially accepted yet by TC39The technical committee behind the ECMAScript specification, but we can start using it today, thanks to Babel.

webpack configuration

We can update our custom .babelrc file as follows:

Javascript (babel-node)
{
"presets": ["next/babel"],
"plugins": [
[
"@babel/plugin-proposal-pipeline-operator",
{ "proposal": "fsharp" }
]
]
}

We can now restart our development server and use this experimental feature.

If we’re interested in using TypeScript as the main development language for our Next.js app, we can just follow the same procedure for adding all the TypeScript-specific plug-ins to our Babel configuration. There are chances that during our Next.js development experience, we may also want to customize the default webpack configuration.

While Babel only takes modern code as input and produces backward-compatible scripts as output, webpack creates the bundles containing all the compiled code for a specific library, page, or feature. For instance, if we create a page containing three components from three different libraries, webpack will merge everything into a single bundle to be shipped to the client. To put it simply, we can think of webpack as an infrastructure for orchestrating different compilation, bundle, and minification tasks for every web asset (JavaScript files, CSS, SVG, and so on).

If we want to use CSS preprocessors such as SASS or LESS to create our app styles, we’ll need to customize the default webpack configuration to parse SASS/LESS files and produce plain CSS as output. The same, of course, occurs for JavaScript code using Babel as a transpiler.

We talk more in detail about CSS preprocessors in the following chapters, but for now, we just need to keep in mind that Next.js provides an easy way to customize the default webpack configuration.

As we saw earlier, Next.js provides a convention-over-configuration approach, so we don't need to customize most of its settings for building a real-world application; we just have to follow some code conventions.

Understanding next.config.js

But if we really need to build something custom, we’ll be able to edit the default settings via the next.config.js file most of the time. We can create this file inside the root of our project. It should export an object by default, where its properties will override the default Next.js configurations:

module.exports = {
// custom settings here
};
The next.config.js file with default settings

We can customize the default webpack configuration by creating a new property inside this object called webpack. Let’s suppose that we want to add a new imaginary webpack loader called my-custom-loader; we can proceed as follows:

C++
module.exports = {
webpack: (config, options) => {
config.module.rules.push({
test: /\.js/,
use: [
options.defaultLoaders.babel,
// This is just an example
// don't try to run this because it won't work
{
loader: "my-custom-loader", // Set our loader
options: loaderOptions,
options
},
],
});
return config;
},
};

So, as we can see, we’re writing a proper webpack configuration that will later be merged with Next.js’s default settings. This will allow us to extend, override, or even delete any setting from the default configuration because although deleting default settings is generally never a good idea, there might be cases where we need it (if we’re brave enough!).