dwyl / learn-typescript

⌨️ Learn how to use TypeScript to enhance your JavaScript skills with type safety.
GNU General Public License v2.0
6 stars 0 forks source link
# Learn `TypeScript` Learn `TypeScript` to enhance your `JavaScript` skills with **_type_ safety**. [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/dwyl/learn-typescript/ci.yml?label=build&style=flat-square&branch=main)](https://github.com/dwyl/learn-typescript/actions/workflows/ci.yml) [![codecov.io](https://img.shields.io/codecov/c/github/dwyl/learn-typescript/main.svg?style=flat-square)](https://codecov.io/github/dwyl/learn-typescript?branch=main) [![TypeScript Version](http://img.shields.io/badge/TypeScript-v5-brightgreen.svg?style=flat-square "Latest Typescript")](https://www.typescriptlang.org/download/) [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat-square)](https://github.com/dwyl/learn-typescript/issues) [![HitCount](https://hits.dwyl.com/dwyl/learn-typescript.svg)](https://hits.dwyl.com/dwyl/learn-typescript)

Why? πŸ€·β€β™€οΈ

You are working on - or planning to work on - a large-scale JavaScript project and don't want the pain of "Uncaught TypeError: undefined is not a function" ... 😒

Who? πŸ‘₯

Any software engineer with (or without) JavaScript skills who wants a better experience. 😍

What? πŸ’­

TypeScript is a superset of JavaScript:

<img src="https://github.com/dwyl/learn-typescript/assets/194400/f66be0cf-6689-4998-a312-fe83031c76bc" width="300" alt="TypeScript superset of JavaScript">

This means it includes all the features we know and love/hate from JavaScript and has many additional features, types and tooling to make our lives easier.

JavaScript is dynamically typed so variables can be assigned any value by the interpreter at runtime based on the variable's value at the time. This is great if you need flexibility while building something fast, but it becomes a problem later when your function needs to know what type of variable it is going to receive.

Quick Example! 1️⃣ + 2️⃣

The advantage of static types is best illustrated by a quick example, a simple addition function in JavaScript:

function add (x, y) {
  return x + y;
}

If we invoke the add function with two numbers:

add(1, 2)
> 3

So far so good. And if we accidentally add a number to a string:

add(1, "hello")
> '1hello'

It still works because JavaScript has type-coerced the 1 to a string and returned a string, in this case '1hello' as the result!

What if somehow a NaN value gets passed into the function?

add(1, NaN)
> NaN

Well now the NaN cascades through the rest of your application without being caught! If you're building an interface for anything in Finance, the last thing you want is a NaN value sneaking in as the result of a simple calculation.

We could add a bunch of "checking" code to our simple add function to "guard" against non-numeric values:

function add (x, y) {
  if(isNaN(x) || isNaN(y)) {
    throw new Error(`Arguments to add function ${x} or ${y} are non-numeric!`);
  }
  return x + y;
}

Adding this kind of code works, but it has to be unit tested.

Note: If you're totally new to Test-Driven Development, consider trying our learn-tdd tutorial.

Even a basic function like add ends up being a lot more lines of code and tests ...

TypeScript prevents this and many other bugs from entering your codebase by simply typing the arguments for the function!

function add(x: number, y: number): number {
  return x + y;
}

Here we have clearly defined the type of the arguments to be number and the return is also a number. If we attempt to invoke the add function with a string (or any other non-numeric value):

add(1, "hello")

the TypeScript compiler will throw a compile time error:

Argument of type 'string' is not assignable to parameter of type 'number'.

Try it for yourself on the TypeScript playground: typescriptlang.org/play

typescript-error-string-not-number

You can use the playground to learn the basics online without installing anything, but if you want to get serious about building something, you'll need to install TypeScript on your machine. ⬇️ πŸ’»

How? πŸ‘©β€πŸ’»

Buckle up! You're in for a ride! 🎒

Install πŸ”½

Install and save typescript as a devDependency:

npm install typescript tsx --save-dev

Extended Example βž•

Create a file called add.ts and add the following lines of code to it:

export function add(x: number, y: number): number {
  return x + y;
}

console.log(add(1, 2))

Once saved, run the the file with the command:

npx tsx add.ts

You should see the output:

3

So we know the file compiles and add function works.

Test add Function

Create a new file called add.test.ts and type (or paste) the following code:

import tap, { Test } from 'tap';
import { add } from './add.ts';

tap.test('add two numbers', (t: Test) => {
  t.equal(add(1, 2), 3);
  t.end();
})

tap.test('add a negative number should work', (t: Test) => {
  t.equal(add(1, -2), -1);
  t.end();
})

This file just imports the tap library and add function from add.ts file.

Then it defines two tests for good measure. Once is the basic 1 + 2 = 3 test and the other adds a negative number which exercises our add function's versatility.

Setup the Testing Library & Scripts

Download the testing library and save to package.json:

npm install tap @tapjs/typescript nyc --save-dev

This will install the following 3 packages:

You don't need to know how any of these work, but if you're curious you can follow the links and read. πŸ”— πŸ‘€

With those devDependencies installed, open your package.json file and add the following scripts definition:

"scripts": {
  "test": "nyc --reporter=lcov tap ./add.test.ts",
  "coverage": "nyc --report html tap ./add.test.ts && open coverage/index.html"
},

This script is just saying:
nyc instrument (collect coverage data for) the following tap test output for the add.test.ts file.

Once you have saved the package.json file. You can run the tests using the command:

npm test

You should see output similar to the following:

> nyc tap ./add.test.ts

 PASS  add.test.ts 2 OK 773ms

  🌈 TEST COMPLETE 🌈

Asserts:  2 pass  0 fail  2 of 2 complete
Suites:   1 pass  0 fail  1 of 1 complete

# { total: 2, pass: 2 }
# time=823.167ms

=============================== Coverage summary ===============================
Statements   : 100% ( 2/2 )
Branches     : 100% ( 0/0 )
Functions    : 100% ( 1/1 )
Lines        : 100% ( 2/2 )
================================================================================

#success

This is an excellent starting point on your TypeScript journey!

Instead of duplicating content here, please see: typescriptlang.org/docs/handbook

Note: we will be extending this doc as needed, but until then, we recommend the official docs!

Relevant Reading & Useful Links