TypeScript is a Static Type-Checker. What does this mean?
The first step to understanding TypeScript is to understand the difference between compile and runtime. And also what makes TypeScript a “compile time thing”.
When is compile time?
let value: string | number = "hello"
This is an example of a TypeScript code. The : string | number
is the TypeScript part. Don’t worry about syntax for now. The JavaScript part is:
let value = "hello"
This is normal JavaScript, and this is what runtime environments like browsers will run. The browser doesn’t run TypeScript code. And this is where compilation comes in.
The TypeScript compiler would take your TypeScript code, and “convert” it into JavaScript which can then be interpreted by runtime environments.
Runtime environments might till have to compile the JavaScript to machine code before executing it.
So all the type checks provided by TypeScript, would happen during the “convertion” from TypeScript to JavaScript:
let value:
string | number
= "hello"
let value
= "hello"
When is runtime?
Runtime happens when the JavaScript code is being executed:
let value = "hello"
function something() {
//
}
something()
Runtime happens when the let value = "hello"
operation runs, when something
is defined, and when something()
is run.
something()
will not be executed during compile time. It will be executed when JavaScript is “running”.
Why does “compile vs runtime” matter to TypeScript?
Static Typing
TypeScript is a static type tool. Static typing means that type checks happen during compile time. And since it is happening during compile time, it means type checking only works for static values.
A good way to look at TypeScript is that TypeScript code is like a draft representation of the expectations of your code:
- this should return a string
- this variable should be of this type
- a different type shouldn’t be passed as an argument
For example:
let value: string | number = "hello"
Here, we are saying value
should be of a string
or number
type. But if you pass a value of a different type, TypeScript will complain:
let value: string | number = "hello"
/**/value/**/ = true
Type 'boolean' is not assignable to type 'string | number' This error got triggered by TypeScript was “converting” the TypeScript code to this:
let value = "hello"
value = true
TypeScript did not run the assignment operation. It did not save value
anywhere in memory with a value of “hello”. It also did not execute value = true
. Think of TypeScript as a checkForTypeErrors
function:
function checkForTypeErrors(typeScriptCode) {
// check for errors
}
This function takes a string—the TypeScript code—then it finds the type errors. If this function comes across something()
, it will not execute it. If it comes across value = true
, it will not execute it. Coming back to this code:
let value: string | number = "hello"
/**/value/**/ = true
Type 'boolean' is not assignable to type 'string | number' Here, you say value
should be a string
or a number
. In checkForTypeErrors
, TypeScript sort of “memorizes” that value
should only ever have a string
or number
type.
If TypeScript sees value = "something"
, it doesn’t say anything. If it sees value = 100
, it doesn’t say anything. But when it sees value = true
, then it throws an error saying “I remember that this should have have a string or number value”.
But very important, TypeScript does not run the code. It only “scans” through the code. Then it compiles it to the JavaScript version.
You help TypeSript help you
Now that we have clarified that TypeScript “scans” your code, but doesn’t “execute” it, we can now come to understand that TypeScript uses the information you provide to help you.
let value: string | number = "hello"
/**/value/**/ = true
Type 'boolean' is not assignable to type 'string | number' Here, you tell TypeScript value
should be string
or number
. When you assign a boolean, TypeScript sees that those types don’t match. Again, TypeScript is using the information you provide to help you.
But take a look at this example:
function getData(): number {
let data // fetch api that returns a string
return data
}
Here we have a getData
function and we tell TypeScript that this function returns a number : number
. Let’s assume that this function, when called, makes an API request that returns a string. In this case, TypeScript does not know what the API actually returns, because it did not run it, so TypeScript will believe you that it returns a number.
function getData(): number {
let data = ""
/**/return/**/ data
}
Type 'string' is not assignable to type 'number' In this case, TypeScript “clearly knows that data
is a string and not a number”, so it throws an error.
Understanding compile and runtime is very important because TypeScript’s “help” happens at compile time. TypeScript cannot use any information that can only be gotten at runtime—for example getting data from local storage, calling an API and so on.