Building Techniques: A Deep Dive into TypeScript

After the fundamentals of building in part1 and a closer look into Go building phase, let’s dive into typescript.

TypeScript, a typed superset of JavaScript developed by Microsoft, has its own unique build process that involves transpilation to JavaScript. Let's explore the various aspects of building TypeScript applications.

TypeScript's Approach to Building

The TypeScript Compiler (tsc)

TypeScript comes with its compiler that translates TypeScript code into JavaScript code.

  • Example:
tsc main.ts

tsconfig.json

The compiler needs to know what to do, and TypeScript offers a large range of configuration options. You can add flags to the tsc command, but it's far better to use the tsconfig.json file. You can either create the file by hand or get a basic one with the command tsc --init.

  • Example:
{
  "compilerOptions": {
    "target": "ES2015",
    "module": "commonjs",
    "strict": true,
    "outDir": "./dist"
  },
  "include": ["src/**/*"]
}

In this file, you will be able to specify the compiler options you want and which files you want to compile. For example, you will be able to specify how you handle modules. TypeScript supports various module systems: CommonJS, AMD, UMD, ES6. If you want to learn more about modules in TypeScript, the official documentation has a whole dedicated section: https://www.typescriptlang.org/docs/handbook/modules/introduction.html

  • Example in tsconfig.json:
{
  "compilerOptions": {
    ...
    "module": "esnext",
    ...
  }
}

You can configure a lot more, but going through it all would take forever and would be really boring. Check out the dedicated section on TS documentation https://www.typescriptlang.org/tsconfig/.

Declaration Files (.d.ts)

Nowadays, a lot of libraries are coded straight in TypeScript, but when a library is coded in JavaScript, it can still be used in your TypeScript project if the library has a declaration file. These files ending with .d.ts are basically the typed interface of the library.

declare namespace helloer {
  function sayHello(s: string): string;
}

The TypeScript team has eased the creation of this file with the generate command: tsc --declaration

Advanced TypeScript Building Techniques

Project References

Project references in TypeScript offer significant benefits for managing large-scale applications. They provide a structured approach to organizing codebases, improving build performance, and enhancing code maintainability.

Without this reference system, when you modify your codebase, TypeScript will compile everything, and your IDE will do the same in the background for type checking. On large codebases, it can consume a lot of resources and take a few minutes.

With these references and a modular approach, you only compile what's being changed. You can have tailored compilation based on your module needs. And last but not least, it allows TypeScript to compile the modules in parallel!

Custom Transformers

I am not really into this one, but it's a really interesting feature that TypeScript allows. Custom transformers are functions that can modify the Abstract Syntax Tree (AST) of your TypeScript code during the compilation process. They allow you to add, remove, or modify nodes in the AST, enabling powerful code transformations and generation.

The reason I don't like transformers is because I feel like they hide stuff from the developers. If there's something I hate when I develop, it's when something looks like magic. When everything works, it's awesome, but when it breaks, nightmare comes.

For the sake of this article, here is a dead simple example:

import ts from 'typescript';

function myCustomTransformer(context: ts.TransformationContext) {
  return (sourceFile: ts.SourceFile) => {
    function visit(node: ts.Node): ts.Node {
      // Perform transformations here
      if (ts.isCallExpression(node) && node.expression.getText() === 'console.log') {
        return ts.factory.createCallExpression(
          ts.factory.createIdentifier('console.warn'),
          undefined,
          node.arguments
        );
      }
      return ts.visitEachChild(node, visit, context);
    }
    return ts.visitNode(sourceFile, visit);
  };
}

The configuration for TypeScript to use the transformer depends on your building system.

Monorepo Builds

We have spoken about having a modular approach in the compilation with project references; let's just take a moment to speak about some useful tools that do similar jobs, like Nx.

While Project References focuses solely on TypeScript compilation, Nx provides broader project management capabilities that can incorporate TypeScript builds alongside other development tasks in a more extensive ecosystem. It supports multiple languages and offers features like dependency visualization and smart command execution, which can really help in managing mono-repos.

Optimization Techniques

To end this post, let's go over two optimization techniques that can make your code faster.

Tree Shaking

Tree shaking is an optimization technique used in modern JavaScript bundlers to eliminate dead code. I hear you say, "It's the developer's duty to clean their code," and you are right! We developers are still human beings and therefore imperfect.

Most of the time, you already use Tree Shaking optimization without knowing it. It's in your favorite framework's production build setup.

Code Splitting

I am sure you already do this, but this one is more important than you may think. By adopting a modular approach and splitting your code into smaller chunks, you get faster loading times.

You can also use dynamic imports to import modules on the go.

And we are done for today! I hope you found some good techniques or interesting insights on how TypeScript software is compiled and how you can improve your loved projects.

Next, we will have a look into the history of building tools.

Until then, happy coding!

0
Subscribe to my newsletter

Read articles from Guillaume Dormoy directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Guillaume Dormoy
Guillaume Dormoy