Setting Up Typescript Project From Scratch
Tags: typescript, javascript, learning, beginners
Published: 2020-11-29 13:54:31

---
title: Setting Up Typescript Project From Scratch
published: true
date: 2020-11-29 10:25:00 UTC
tags: typescript,javascript,learning,beginners
canonical_url: https://www.theminimalistdeveloper.com/setting-up-typescript-project-from-scratch/
---

Originally posted on [The Minimalist Developer](https://www.theminimalistdeveloper.com/setting-up-typescript-project-from-scratch/)

[![Start building](https://www.theminimalistdeveloper.com/static/b05094a690cb6d46289f21b263d47a0d/59822/post-image.png "Start building")](/static/b05094a690cb6d46289f21b263d47a0d/11a8f/post-image.png)

## TL;DR

You don’t want to read through all those steps? Dive in straight into coding, just clone/download/fork [this repository](https://github.com/theminimalistdeveloper/base-typescript-project) with the resulting base project of this post 😀.

## Introduction

Whenever learning a new language after [configuring a proper development environment](https://dev.to/theminimalistdeveloper/setting-up-neovim-for-typescript-development-57dl), set up a project from scratch is the next step on my list.

To understand how to have everything in the right place to start coding is essential. Of course, after the first few times, you will probably automate these steps or would rely on some boilerplate project.

The idea of this post is to walk through the very first steps necessary to have a project correctly set up for Typescript, and by correctly, I mean having these things in place:

- **Project structure** : Folder structure, Git, NPM
- **Unit test setup** : Jest
- **Style guide** : Airbnb style guide for Typescript
- **NPM Scripts** : Wrap up common commands in NPM scripts
- **Pre commit hooks** : To ensure we don’t tarnish our immaculate repository

This structure could be used for front-end development, probably with some tweaks here and there. But for my purpose and also for the post, it is oriented for backend development.

Also, everything here is aimed towards **\*nix** environments, either be some Linux flavor or MacOs, with **NodeJS** and **Git** installed.

## Setup

### 1 - Initiate the Project

Define the folder name that will house our project. In this case, let’s call it **ts-project**.

```Bash
mkdir -p ts-project/{src,tests/unit/src}
```

The above command will generate this structure:

```
ts-project
├── src
└── tests
    └── unit
        └── src

```

Hop into the project’s folder.

```Bash
cd ts-project
```

Initiate an empty Git Repository:

```Bash
git init
```

Add a **.gitignore** file at the root of the project with the following content:

```
node_modules/
dist/
```

Which will tell Git to not track the changes on those folders.

Initiate an NPM project. The **-y** tells NPM to accept all the default settings:

```Bash
npm init -y
```

Install Typescript:

```Bash
npm install --save-dev typescript
```

Do not ignore the —save-dev flag. It tells NPM to add the Typescript package to the dev dependency list on our newly added **package.json**.

Initiate Typescript by issuing:

```Bash
npx tsc --init
```

This line deserves a word or two. Alongside NPM, it is installed another tool called [NPX](https://www.npmjs.com/package/npx). NPX is a tool to execute binaries without having them installed globally. It will look for the executable first at the environment variable $PATH, then in the local project for the requested command, in this case, tsc.

The **tsc** portion of the command refers to the Typescript dependency. When executed, the above command should display something like this as a result:

```
message TS6071: Successfully created a tsconfig.json file.
```

It creates a configuration file called **tsconfig.json** with parameters necessary for Typescript to work properly.

By default, all possible configuration keys are present, but most of them, will be commented out. After cleaning up the unnecessary commented lines you will be left with something like this:

```JSON
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}
```

For a detailed description of what each of these fields means, please check the official documentation right [here](https://www.typescriptlang.org/tsconfig).

Let’s tweak this a little bit. Add two new keys to the compiler options

```JSON
"outDir": "dist",
"sourceMap": true
```

- **outDir** : being the destination folder of the transpiled code will be stored, in this case, we go with the most common of all, dist.
- **sourceMap** : enables the generation of source map files. They allow debuggers and other tools to show the original Typescript when debugging the compiled Javascript.

And at the root we add:

```JSON
"include": ["./src/**/*"]
```

Which tells the compiler to take everything from the source (src) folder.

The end result is something like this:

```JSON
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "dist"
  },
  "include": ["./src/**/*"]
}
```

### 2 - Unit Tests

For unit tests, I have been using [Jest](https://jestjs.io/en/) for quite some time now, no complaints.

Very straight forward and simple testing framework.

To install all the packages necessary run:

```Bash
npm install --save-dev \
  jest \
  babel-jest \
  @babel/core \
  @babel/preset-env \
  @babel/preset-typescript \
  @types/jest
```

Then add a **babe.config.js** at the root of the project with the content:

```JSON
module.exports = {
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' } }],
    '@babel/preset-typescript',
  ]
};
```

And our testing setup is done.

### 3 - Style guide and linting

This is a crucial step to ensure, among other things consistency. I am have been working with the [Airbnb style guide for Javascript](https://github.com/airbnb/javascript) for almost two years, and love it. Helps to fix smaller mistakes literally pointing out to you.

To be able to use the same ruleset on Typescript, we are going to use a package called [eslint-config-airbnb-typescript](https://www.npmjs.com/package/eslint-config-airbnb-typescript), which is a drop-in replacement for the normal **eslint-config-airbnb** but with all the Typescript goodness.

To install, run the following:

```Bash
npm install --save-dev \
    eslint \
    eslint-config-airbnb-typescript \
    eslint-plugin-import@^2.22.0 \
    @typescript-eslint/eslint-plugin@^4.4.1
```

And add **.eslintrc.js** to the project root with the content:

```JSON
module.exports = {
  extends: ['airbnb-typescript/base'],
  parserOptions: {
    project: './tsconfig.json',
  },
};
```

In case you went through my last post ”[Setting up Neovim for typescript development](https://dev.to/theminimalistdeveloper/setting-up-neovim-for-typescript-development-57dl)” you will notice that this style guide uses Eslint, and we configured the only tsserver. To add Coc support for Eslint run:

```VIM
:CocInstall coc-eslint
```

Check out its [documentation](https://github.com/neoclide/coc-eslint) to learn more about the extension.

### 4 - NPM Scripts

Let’s leverage the [NPM scripts](https://docs.npmjs.com/cli/v6/using-npm/scripts) system to facilitate interacting with the tooling we just set up.

This seems like a trivial, maybe unnecessary step, but having the tooling abstracted by the scripts can help to decouple it from other parts like some editor shortcuts or CI/CD pipelines. So in case, you decide to change your testing library or build process, we can simply change it in one place.

Add this piece of code at the root of the package.json:

```JSON
"scripts": {
    "test": "jest",
    "lint": "eslint",
    "compile": "tsc"
}
```

These are pretty self-explanatory, but here are examples of how we can use these scripts. From the project root run:

```Bash
# This will run the testing library Jest
npm run test
# This will run the linting
npm run lint
# This will run the compilation
npm run compile
```

### 5 - Pre-Commit Hooks

Finishing up with some fail-safes, it can make our lifes much easier. [Git hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) is a neat feature from Git, it allows us to run scripts in certain key events like before applying a commit, before pushing, and many others.

In this example, we will use a package called [pre-commit](https://www.npmjs.com/package/pre-commit) to run our scripts before the commits. To install it, run:

```Bash
npm install --save-dev pre-commit
```

And then add this to package.json:

```JSON
"pre-commit": [
    "test",
    "lint",
    "compile"
],
```

This will make sure that every time you issue a commit command, runs all the three npm scripts. That way, we will never be able to event commit broken or invalid code.

### 6 - Testing

With everything in place, let’s write a “hello world” and test it. Add an **index.ts** to your **src** folder, located at the root of the project with this content:

```Typescript
/**
 * Hello world function
 *
 * @param {string} name
 */
function helloWorld(name: string) {
  return `Hello world, ${name}`;
}

export default helloWorld;
```

And add an **index.spec.ts** at **tests/unit/src** with this content;

```Typescript
import helloWorld from '../../../src/index';

test('Hello world works', () => {
    expect(helloWorld('Foo'))
        .toBe('Hello world, Foo');
});
```

Now, from the command line at the root of the project, run:

```Bash
npm run lint && npm run test && npm run compile
```

Which should result in something like this:

```Bash
> ts-project@1.0.0 lint /Users/username/ts-project
> eslint

> ts-project@1.0.0 test /Users/username/ts-project
> jest

 PASS tests/unit/src/index.spec.ts
  ✓ Hello world works (2 ms)

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.898 s, estimated 1 s
Ran all test suites.

> ts-project@1.0.0 compile /Users/username/ts-project
> tsc
```

We’ve made it!

## Conclusion

These kinds of steps are valuable to understand all the moving parts that compose a base project structure, but after a couple of times, these steps should be automated or a boilerplate that fits your needs created.

We went through all the steps to set up a solid foundation for our experiments and projects. Now the only thing left is to build something cool.