Setting up a Simple TypeScript Project

August 2017

This is a very small tutorial on how to setup a TypeScript project:

  • How to create a project
  • How to compile
  • Explore compiler options
  • Using a tsconfig.json file

For this tutorial you will need to have the following installed

  • Node (download from here)
  • Yarn (from here or install using npm)

Setup (very first steps)

Open a terminal and create a new directory to work on our demo application.

$ mkdir demo && cd demo

Let's first initialise a new yarn project and using default values (the -y option does not prompt for questions):

$ yarn init -y

You should now have a package.json file inside your directory. Next you can add a dependency to typescript (let's fix the version of typescript)

$ yarn add typescript@2.4.2 --dev

We have not installed typescript globally, only local for this project. This makes it easier to manage your typescript versions.

let's create our first typescript (cough) file:

function say(what){
  console.log(what);
}

var txt = "hello friend";

say(txt);

You are now ready to compile (you need to use yarn as you are running tsc locally from the node_modules directory and not from a globally installed typescript compiler.)

$ yarn tsc src/hello.ts

Yes!, you have compiled your first typescript file (cough). You should have a transpiled javascript file src/hello.js

You can run this file using node:

$ node src/hello.js

Voila it should print "hello friend".

Well too be honest you have not really used any of the typescript syntactic sugar. Typescript is a superset of ECMAScript, and that's what you used. If your would do a diff on the original and transpiled file you would notice there are no differences:

$ diff src/hello.ts src/hello.js

Using the watch option

Just before we continue : you can also pass a watch option that scans your input files for changes and compiled automatically upon a change:

$ yarn tsc -- --watch src/hello.ts

A note on the double hyphen (--): This allows us to pass additional arguments to the command (in this case we are passing --watch to tsc. Without he double hyphen the --watch would be passed to yarn itself)

Using some real TypeScript

Let's spice things up a bit and use some of the syntactic sugar provided by typescript:

Add a type annotation to the what parameter of say: function say(what: string)

Transpile and run your file again. The result should be the same. Do notice the generated javascript file is now different from your typescript one.

$ diff src/hello.ts src/hello.js

Now change the value of the txt variable to 12 (as in the number 12): var txt = 12;.

When you try compile your file now, you should get the following error

src/hello.ts(5,5): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.

Change it back to a string to make it compilable again. Next we explore using different compiler options.

Compiler Options

Let's list the command line options of the compiler:

$ yarn tsc -- -h

Target

Notice the default value for the --target is es3. Let's see this in action.

Change your txt variable declaration to a constant one: const txt = "hello friend";.

$ yarn tsc src/hello.ts

Compile and notice the transpiled javascript uses var. This is because const was introduced in es6. Let's compile with this target and see what happens:

$ yarn tsc -- -t es6 src/hello.ts

You will now find the compiler has transpiled your statement to use const

strictNullChecks

We will explore another option. By default null and undefined are bottom values. This means every variable can be assigned their values (so in other words the value space of txt include strings as well as null and undefined.). You might want to read-up on Null References: The Billion Dollar Mistake.

Since typescript 2.0 we can exclude null and undefined from the value-space of other types. This way you can't by accident place a null value where you were not expecting it.

To illustrate, add a function shout:

function shout(what : string){
    const loud = what.toUpperCase();
    console.log(loud);
}

Call the function once with a value, and once with null (which is allowed!):

shout("shout, let it all out")
shout(null)

You should see your first message, and then the infamous error message: "cannot read property … of null".

Let's now compile it with the strictNullChecks option:

$ yarn tsc -- -t es6  --strictNullChecks  src/hello.ts

Observe the error you received:

src/hello.ts(13,7): error TS2345: Argument of type 'null' is not assignable to parameter of type 'string'.

If you would still like to allow people to pass null (blech), you could declare the what parameter as a union type: (what: string | null)

When you compile, you'll notice passing null (blech) is syntactically correct, however there's a problem now when you access the what parameter as it might be null. What should the function's semantics be in case null is passed? Perhaps we don't shout anything:

function shout(what : string | null){
    if (what){
        const loud = what.toUpperCase();
        console.log(loud);
    }
}

This is now a rather silly function: we are allowing null to be passed, but then we don't do anything. The option where we did not allow for null seems a better solution. But leave if for now.

You have used two compiler options and every time you call the compiler, you must pass these arguments. In general it is better to create a tsconfig.json file instead. You'll be exploring that next.

Using tsconfig.json file

A tsconfig.json contains the configuration for your typescript project. You can have tsc generate one for you, by passing it the --init option:

$ yarn tsc -- --init

Compiler options

When you open the file, you'll notice it gives you a head-start plus a whole bunch of options commented out. Feel free to explore this list. Eventually you should only include the following:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "sourceMap": true,
    "inlineSources": true,
    "strictNullChecks": true
  }
}

You can now run the compiler without any command line options:

$ yarn tsc

Include/Exclude (fyi)

By default tsc picks up all typescript files (.ts, .d.ts and .tsx) files in the containing directory and its subdirectories except those excluded by default (such as node_modules and bower_components, see handbook for exact defaults)

You can use the following options:

  • files: an array of filenames to include
  • include: an array of glob-like patterns
  • exclude: an array of glob-like patterns to exclude files from include (has no effect on explicitly listed files)

We won't have to do anything as the default works for us.