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"
... 😢
Any software engineer
with (or without)
JavaScript
skills
who wants a better experience. 😍
TypeScript
is a
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.
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
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. ⬇️ 💻
Buckle up! You're in for a ride! 🎢
Install and save typescript
as a devDependency
:
npm install typescript tsx --save-dev
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.
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.
Download the testing library and save to package.json
:
npm install tap @tapjs/typescript nyc --save-dev
This will install the following 3 packages:
tap
- simple testing library node-tap.org@tapjs/typescript
- tapTypeScript
plugin https://tapjs.github.io/tapjs/modules/_tapjs_typescript.htmlnyc
- test/code coverage library https://github.com/istanbuljs/nyc
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!
- Home: typescriptlang.org
- What is
TypeScript
and Why You Should Use It For Your Next Project? https://prismic.io/blog/what-is-typescript - What problem does
TypeScript
solve? https://dev.to/ricardopaul/what-problem-does-typescript-solve-5fka - Getting started with
TypeScript
: https://dev.to/newswim/getting-started-with-typescript-25l9 - How to run
TypeScript
files from command line? https://stackoverflow.com/questions/33535879/how-to-run-typescript-files-from-command-line