Daniel Doubrovkine bio photo

Daniel Doubrovkine

aka dB., @awscloud, former CTO @artsy, +@vestris, NYC

Email Twitter LinkedIn Github Strava
Creative Commons License

I’ve done a fair amount of JavaScript, here and there, and have written some TypeScript, too. But I’ve never actually started anything in TypeScript. Attempting a basic “hello world” in TypeScript turned out to be completely non-trivial, so this should help you.

Editor

I use Visual Studio Code.

Node

Setup node.js. I use nvm, whatever recent version of node and npm.

$ node --version
v12.1.0

$ npm --version
6.9.0

Ts-Node

TypeScript comes with an execution and REPL for node.js called ts-node.

$ npm install -g typescript ts-node

$ ts-node --version
v8.3.0

Hello World

Create a file called hello.ts. It’s JavaScript disguised as TypeScript for now.

console.log('hello world');

Run it.

$ ts-node hello.ts 
hello world

Underneath ts-node this file got transpiled into JavaScript with tsc hello.ts, the TypeScript compiler and executed. We can do this ourselves as follows.

$ tsc hello.ts

$ node hello.js
hello world

Asynchronous Code

Let’s write a basic function that returns a value.

function f() {
  return "returned from f"
}

console.log(f());

Make it asynchronous by returning a promise. You can run this with node async-function.js.

function f() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve("returned from f after a second");
    }, 1000);
  });
}

f().then(function(result) { 
  console.log(result); 
});

Now we can rewrite this in TypeScript and use ES6 fat arrows. We add a type to f(), expressing that the function must promise (return a Promise) to return a string. We mark everything asynchronous with async, and use await to wait for the asynchronous f to finish.

async function f(): Promise<string> {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("returned from f after a second");
    }, 1000);
  });
}

async function main() {
  const result = await f()
  console.log(result);
}

main();

The async/await pair is a lot nicer than having to use then and having types removes all the guesswork from what functions return.

If you just run this with ts-node without any arguments you will have a few issues.

error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor.
error TS2585: 'Promise' only refers to a type, but is being used as a value here.

These are fixed by calling the compiler with --lib es6.

error TS2304: Cannot find name 'setTimeout'.
error TS2584: Cannot find name 'console'. 

These are fixed by including a target library with --lib dom.

Both arguments are required to run our code with ts-node.

$ ts-node -O '{"lib":["dom","es6"]}' async-function.ts
returned from f after a second

Config

Having to specify -O with a JSON for every invocation of ts-node is annoying. You can create a file called tsconfig.json with this configuration.

{
  "compilerOptions": {
  "lib": [
    "es6",
    "dom"
  ]
  }
}

It gets loaded automatically.

$ ts-node async-function.ts 
returned from f after a second

Adding Lodash

$ npm install --save lodash @types/lodash 

Better, create a package.json and run npm install.

{
  "name": "typescript-hello-world",
  "version": "1.0.0",
  "dependencies": {
  "@types/lodash": "^4.14.53",
  "lodash": "^4.12.0"
  }
}

This creates node_modules/lodash and node_modules/@types/lodash, which includes lodash TypeScript definitions.

Now that we have dependencies we can introduce some project structure. The code should live in src/index.ts.

import * as _ from "lodash";

async function f(): Promise<string> {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("returned from f after a second");
    }, 1000);
  });
}

async function main() {
  const results = await Promise.all(_.times(3, f));
  console.log(results);
}

main();

And an updated tsconfig.json.

{
  "include": [
    "src/**/*"
  ],
    "exclude": [
    "node_modules",
  ],
  "compilerOptions": {
    "lib": [
      "es6",
      "dom",
    ]
  }
}

Run it.

$ ts-node src/index.ts 
[
  'returned from f after a second',
  'returned from f after a second',
  'returned from f after a second'
]

The code for this post can be found here.