Typescript's Heartbeat: A guide to TSC Compiler

Typescript's Heartbeat: A guide to TSC Compiler

Typescript, as we all know, enhances the development process with its static typing and advanced features. But what happens behind the scenes when you write typescript code? How does it magically transform into browser-friendly Javascript? So, in this blog, we'll have a look at the Typescript Compiler or 'tsc' as we call it. Whether you are new to TS or are an experienced developer, understanding the tsc is your key to mastering this language.

Introduction

First of all, I'm hoping you know a bit about TS, what is it, and why we need it. If you don't, I would suggest reading my previous blog: https://gaurav750.hashnode.dev/basic-types-in-typescript. That should give you the basic idea of TS.

When developers talk about TS, they often praise its advanced features like static typing, interfaces, and generics - that aren't native to JS. While these features are great while building a scalable and robust application, there's a catch: browsers, at their core, don't understand TS. They only understand Javascript. TS, in its raw form, is not something you can run directly into the browser.

So, how do we bridge this gap? How do we still take advantage of TS and still produce something that browsers can run?

Enter the Typescript compiler, commonly known as 'tsc'. The 'tsc' compiler acts as a translator, taking your TS code - and outputting a plain, browser-friendly Javascript code (btw, this process is known as transpilation). So, you get the best of both worlds, you get the advanced features of TS, and you can still run your code into any browser.

Before diving more, just check whether you have Node.js and typescript installed. To install Node.js you can visit here: https://nodejs.org/. To install Typescript, open your terminal or command prompt and type the following command to install TS globally, making the 'tsc' available globally as well.

npm install -g typescript

You can then check the version using tsc --version command, ensuring that you've successfully installed TS and are ready to go!

Basic Compilation

As we know by now, browsers understand JS, not TS. This is where the process of 'transpilation' comes in. Using the tsc command - we can transform the Typescript code into native Javascript code.

tsc filename.ts

Here, tsc stands for TypeScript compiler, and filename.ts should be replaced with the name of your TypeScript file.

When you execute this command, a few things happen:

  1. Type checking - The compiler reviews the TypeScript file to ensure there aren't any type mismatches or errors. If it encounters issues, it will display them in the console (so, we get an advantage of TS!).

  2. Transpilation - If everything's good, the compiler converts the TS code to equivalent JS code. Here, it removes the type annotations and anything which is TS specific.

  3. Output - After the process is complete, you'll notice a new file in the same directory named filename.js (your file name). This contains the JS code which you then can run into any browser.

e.g.

let title: string = "Typescript's Heartbeat: A guide to TSC Compiler!";
console.log(title);

When you run the command tsc filename.ts, the Typescript compiler will generate a filename.js file:

let title = "Typescript's Heartbeat: A guide to TSC Compiler!";
console.log(title);

Notice how the type annotation :string is removed in the JavaScript output. This illustrates the compiler's role in transitioning from the statically typed TypeScript to the dynamic nature of JavaScript.

You can also enter watch mode - means you won't need to run the tsc filename.ts command every time you change anything.

tsc filename.ts --watch
//or
tsc filename.ts -w

If you just run tsc -w command, it'll compile all the ts files present in the project, if you haven't configured what files to include/exclude in tsconfig.json. So, using just tsc without any filename will use the configuration from the tsconfig.json. We'll see how we can do that as well.

Configuration using tsconfig.json

In Typescript, the tsconfig.json file serves as a central hub for configuring the TS compiler's behavior. Rather than passing numerous command line arguments every time, this config file provides a standardized way to specify the compiler options.

Now, you can manually create a tsconfig.json file in your project and then manually add all the options, or, you can use tsc --init command. When you run this command, a tsconfig.json file with default settings and extensive comments will be created in the current directory.

Now, let's look at some commonly used options in tsconfig.json.

  • target - This determines the ECMAScript target version for the output JavaScript files. Modern browsers support all ES6 features, so ES6 is a good choice. You might choose to set a lower target if your code is deployed to older environments, or a higher target if your code is guaranteed to run in newer environments.

    The target setting changes which JS features are down-leveled and which are left intact. For example, an arrow function () => this will be turned into an equivalent function expression if target is ES5 or lower.

    Also, if your target is ES5, then let and const will be translated to var.

  • include - Specifies an array of filenames or patterns to include in the program. files option is similar & is useful when you only have a small number of files, and there you can only specify files, you cannot use wildcards to reference many files, which you can use in include and exclude btw.

  • exclude - You can specify the path to files that need not be compiled. The exclude array contains filenames or patterns that should be skipped when resolving the include array.

    The exclude option changes what the include option finds, effectively filtering out some folders or files from compilation.

  • rootdir - Basically, it tells the TS compiler where to look for TS files. When the project gets bigger, the normal convention is to keep all the source files in the src folder and all the output files in the dist folder.

  • outdir - As explained above, all the emitted .js files will be stored in the directory specified in outdir.

    The tsc will also maintain the folder structure. E.g. if you have sub-folders in src folder, same folder structure will be maintained in the dist as well.

  • lib - It contains the type definitions/libraries for things found in browser environments (like document) and also for built-in JS APIs (like Math). Come to think of this code:

    Why isn't TS yelling at us for 'document'? We haven't defined it anywhere. This is because of the lib default settings. It contains "DOM", "DOM.Iterable", "es6", "scripthost" by default.

  • noEmitOnError - If there is an error in any TS file, the compiler won't emit/generate the .js file. This defaults to false, making it easier to work with TypeScript where you may want to see results of changes to your code before resolving all errors.

  • strict - The strict flag, when enabled, activates a wide range of type-checking behaviors to make sure your code is as type-safe and error-free as possible. Turning this on is equivalent to enabling all of the strict mode family options like noImplicitAny, strictNullChecks, alwaysStrict, etc.

There are various other options present in the tsconfig.json file like module, allowJs, etc which you can explore if there's a need for it in your project.

So.. we saw how can we use tsconfig to configure the TS compiler to compile however we want. Understanding the TypeScript compiler's options is an investment in becoming a more effective developer. It's about writing code that not only works but is built upon a strong, type-safe foundation.

That is it for this blog. Let's meet again where I'll be talking about.. I don't know either 😂!

Thank you for staying till the end!