Blog A.Wolf

Blog Posts

No results for 'undefined'
Powered by Algolia
How to create a Node.js App with TypeScript?

How to create a Node.js App with TypeScript?

December 6th, 2019 - 7 min read

We're creating a Node.js setup with Typescript compiler (short TSC) from scratch, so you can use Typescript for your next Node.js app.

I'll guide you through each step from start to finish so you can start with your app development.

We're not creating any demo app as I want to focus on the setup of the project.

The setup will contain:

  • Typescript configuration for a Node.js app
  • Node dev. setup with source file watching
  • Prettier for formatting your code
  • TSlint for linting (see note at the end of this post about the "future of TSlint")
  • Jest for unit testing

Yarn or Npm

I'm using Yarn here but if you prefer Npm that's also OK. Just replace everything with Npm commands npm install ... or npm run ....

I'm using Yarn because I think there are still some benefits that Npm doesn't offer. Just to mention some:

  • Easy to use workspaces with-out an external library. With Npm you would need something like Lerna.js
  • Speed - Yarn is slightly faster
  • I'm preferring the commands - add vs install and to execute commands with-out run.

So both are OK to use, the only thing I recommend is stick to either Yarn or Npm in your team and don't mix them as having both lock files is a problem.

Create a new project

Run mkdir my-node-app && cd my-node-app and yarn init -y. Next, install the dependencies with yarn add nodemon typescript @types/node ts-node tslint tslint-config-prettier prettier rimraf -DE this will add the following packages as development dependencies to your project:

  • Typescript... that's the compiler, so you can call it with tsc
  • @types/node... Node.js type definitions
  • Nodemon... to watch and run our app during development
  • Ts-node... to run Typescript compiler with Node.js
  • TSlint... needed for prettier
  • Tslint-config-prettier... configuration of prettier.
  • Prettier... for making our code prettier
  • Rimraf... just for cleaning build folder ./lib in a cross-platform manner

The last part -DE in the command means to install these as dev. dependencies and pin the version with -E, --exact option. More about version pinning can be found in this post.

Create a Typescript config file with node_modules\.bin\tsc --init (or tsc --init if you have Typescript installed globally). This will add a tsconfig.json file to your project. Now, we need to modify the file a bit for our setup:

  • outDir: './lib' - line 15 - Output folder of the generated code
  • rootDir: './src' - line 16 - This is the folder where Typescript will look for source files
  • "resolveJsonModule": true - Add that to your configuration to enable typed JSON imports.
  • "esModuleInterop": true - Already configured and needed so that CommonJs imports are compatible with ES6 modules. More details about it, in this SO question.
  • "module": "commonjs" - This allows us to define the output module type. commonjs is the standard module format used in Node.js, therefore this is what we will adhere to.
  • "moduleResolution": "node" - Uncomment this in line 42. Typescript attempts to mimic Node’s module resolution strategy.

Create a tslint.json in the project root with the content:

{
  "extends": ["tslint:latest", "tslint-config-prettier"]
}

Enable linting in your project with VS Code settings.json as mentioned in the VS code setup post. Just replace ESLint in the settings.json with:

{
  // ... other config ...,
  "editor.codeActionsOnSave": {
    "source.fixAll.tslint": true
  }
}

Now it will automatically format your code on save with Prettier and Tslint.

For development, we're adding the Nodemon configuration to a nodemon.json to the project root (as that's easier than passing everything as a command-line argument):

{
  "watch": ["src"],
  "ext": "ts",
  "ignore": ["src/**/*.spec.ts"],
  "exec": "ts-node ./src/index.ts"
}

Next, we'll add our start & build scripts to the package.json:

{
  // other content of package.json
  "scripts": {
    "start": "nodemon",
    "build": "tsc -p .",
    "clean": "rimraf lib",
    "prebuild": "yarn clean"
  }
}

yarn start is used for development and that's starting Typescript and finally runs Node.js with your index script. Nodemon is also watching your source code and automatically re-runs TSC to update your code.

Configure Git

Run git init and create a .gitignore file:

# Log files
*.log

# Ignore our build files
lib

# Ignore node dependencies
node_modules

You can test if your ignore file is right by running git status and keep in mind that you don't want to commit any generated files or log messages.

First test of the setup

Add the index.ts to src/ folder:

const message:string = 'Yay! This works!';
console.log(message);

Run yarn start and you should see the greeting Yay! This works! in the console.

To build your project run yarn build. Once build finished, you can test your app with node ./lib

You can try if Typescript is doing it's job by changing the string 'Yay! This works!' to a number. TSlint will mark the type error and in the console you'll also get it as a message.

Add unit tests with Jest

Other test runner frameworks would also work (e.g. Mocha, Jasmine, Karma, Ava, etc.) but I'll use Jest as it will fully support Typescript.

Run yarn add jest ts-jest @types/jest -DE to add it.

To the project root, add the jest.config.js file:

module.exports = {
  globals: {
    "ts-jest": {
      tsConfig: "tsconfig.json",
    },
  },
  moduleFileExtensions: ["ts", "js"],
  transform: {
    "^.+\\.(ts|tsx)$": "ts-jest",
  },
  testMatch: ["**/test/**/*.test.(ts|js)"],
  testEnvironment: "node",
};

This config is telling ts-jest which TS config to use and that our test files are in test folder. The transform is used so Jest knows that we'd like to use TS-Jest preprocessor for our files with .ts extension.

We can add "test": "jest" to our scripts in package.json, so we can run yarn test to start our tests.

Add a file called hello.test.ts to the folder ./test:

describe('My module to test', () => {
  it('should pass', () => {
    expect(true).toBeTruthy();
  });
});

Now, run your first test with yarn test and you will get one passing test. It's not testing anything but you should get an idea. Screenshot Jest result example

If you're new to Jest, I'd recommend having a look at the Jest getting started guide.

New to Typescript

To learn about Typescript I would start with the Typescript in 5 Minutes guide.

If you're looking for type definitions, I'd recommend the TypeSearch page from Microsoft. Just enter the package where you need types and the search result will redirect you to the Npm.js page of that package. You could also search directly on Npm.js by looking for @types/... packages.

What's next

Your setup is ready for your next Node.js project. You can create a Web server, a JSON API server or a command-line interface (CLI) tool and a lot more...

A web or API server could be created with express.js and a CLI with Commander.js.

For a CLI tool, you could also checkout oclif but with it, you don't need the setup mentioned above as it includes a generator for your project. So I would probably start with Commander.js as you're already having everything in place (if you followed this guide).

I'll write a post about a CLI that I'm creating. It's a license selection tool for a project. So you can run choosealicense add mit. It will generate a LICENSE file and add the license key to your package.json. I know that similar tools are available but I want to create it to learn how to create a CLI and to have every feature as I want it.

If you're building somthing with Node.js, please let me know what you're building. I'm always interested in new ideas. You can add a comment here or drop me a line on Twitter.

You can find the source code in the following Github repository.

Good luck & Happy Coding!

Future of TSlint

I read in a post that Tslint will be deprecated in favor of typescript-eslint.

I don't know if Typescript-eslint tooling (VS code extension + ts-eslint) is ready but I'll check it and write about my experience once I've tested it.

©2020 Alexander Wolf