TypeScript, Understanding the code you write
TypeScript has given the frontend a powerful chance to deliver reliable and maintainable code. The more you correctly type your code, the more you fall into its strengths and importance. In this post, I'll mention some TypeScript tips that you may or may not know about.
How TypeScript works?
The first thing you should know is how TypeScript works?
Browsers are designed to only understand JavaScript, just as computers are designed to only understand zeros and ones. In the case of computers, we compile high-level code to machine code and then to zeros and ones so the computer can understand it. Similarly, we transpile or translate TypeScript code to JavaScript code to be understood by browsers and other engines that only know JavaScript.
To do this, we may use the popular tsc
tool, You can also check out the awesome-typescript-compilers repository to learn more about them.
For example, code like this:
type animals = "cat" | "dog";
const getAnimal = (animal: animals) => animal;
getAnimal("cat");
Is translated to this JavaScript code, so browsers can understand it:
const getAnimal = (animal) => animal;
getAnimal("cat");
Note: TypeScript code is eliminated in the transpiling process.
This leads us to an important conclusion: once you realize it, you'll notice a lot about TypeScript concepts and why they've been written in their particular way.
Conclusion: As TypeScript does not run on browsers, it only runs at compile time, not at runtime.
Compile time is the time when your code is being built, before it runs and becomes interactive. Run time is when your code is running and interacting with the client.
Differences in Action
Let's compare a typed language that checks types at runtime, like C#, with TypeScript, which checks types at compile time:
Function overloading
Some JavaScript functions can be called in a variety of argument counts and types. For example, you might write a function to produce a
Date
that takes either a timestamp (one argument) or a month/day/year specification (three arguments). Resource
In C#, we can achieve function overloading by declaring multiple function arguments and bodies. This is possible because C# checks the type of the function arguments at runtime and defines the function body accordingly:
void display() { ... }
void display(int a) { ... }
float display(double a) { ... }
float display(int a, float b) { ... }
However, in TypeScript, we go to the runtime without types, without typescript itself, so there's no runtime type checks and then we can't assign multiple values to the same variable in javascript, or in other words we can't create multiple bodies for the same function.
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(m: number, d: string, y: number): string;
function makeDate(
mOrTimestamp: number,
d?: number | string,
y?: number
): Date | string {
if (typeof d === "string") {
return "hello";
}
if (d !== undefined && y !== undefined) {
return new Date(y, mOrTimestamp, d);
} else {
return new Date(mOrTimestamp);
}
}
const d1 = makeDate(1234);
const d2 = makeDate(5, 5, 5);
This will be compiled to this Javascript code:
function makeDate(mOrTimestamp, d, y) {
if (typeof d === "string") {
return "hello";
}
if (d !== undefined && y !== undefined) {
return new Date(y, mOrTimestamp, d);
} else {
return new Date(mOrTimestamp);
}
}
const d1 = makeDate(1234);
const d2 = makeDate(5, 5, 5);
There's libraries can do runtime checks for javascript, one of the most popular libraries do this is zod you can give it a try.
Narrowing (make it more specific)
keyof
and typeof
keyof
from its name, used to "extract" a key of a TYPE, and since objects are the only datatype that contains keys, thenkeyof
is used to extract key of an object in a union format
type obj = { [n: number]: string };
type A = keyof obj; // number
typeof
from its name, used to return thetype
of a variable. simple!
let str = "Alia";
type a = typeof str; // string
const str2 = "Alia";
type b = typeof str2; // "Alia"
Important note: I used let
here instead of const
. If I used const
, then the type would be the specific string value itself.
Let's merge both
const obj = {
id: 1,
name: "Alia",
}; // javascript variable no types
type typeOfObj = typeof obj; // type of the javascript object
type keysOfObj = keyof typeOfObj; // id | name
type keysOfObjOneLine = keyof typeof obj;
Notice here
keyof
extracts keys of type (object).typeof
extracts the type of variable.
keep this in your mind for the mapped types section.
in
operator and extends
Similar to the previous section, in
operator is kinda similar way you can use it to limit the key to be within a group of types
type keysOfObj = "id" | "name";
type obj = { [key in keysOfObj]: string };
// type obj = {
// id: string;
// name: string;
// }
But we need to modify the code to fix the type for the id
key to be number
not string
extends
consider it asif else
of typescript.
type keysOfObj = "id" | "name";
type obj = { [key in keysOfObj]: key extends "id" ? number : string };
// That's it
This called mapped types
Generics
Think about it as a function in javascript, if you have a type and you're repeating it with slight changes, then you probably need to use generics
.
interface BasicType<T> {
input: T;
}
const x: BasicType<string> = { input: "test" };
const y: BasicType<number> = { input: "test" }; // wrong
function basic(a, b) {
return { a, b };
}
function basic<A, B>(a, b) {
return { a, b };
}
function basic<A, B>(a: A, b: B): { a: A; b: B } {
return { a, b };
}
basic<string, number>("hello", 2);
we can still use extends
with generics to give a powerful type.
Typescript Coverage
In addition to adding TypeScript rules to your project, it's important to track TypeScript code coverage. Code coverage helps identify missing types for variables.
You might think it's obvious if a variable has a type, but when using third-party libraries, classes, or functions, it's easy to miss some. Not everything, such as query parameters, will be tracked by the TypeScript coverage library, but it definitely helps.
I suggest using typescript-coverage-report for this purpose. If you know of a better option, feel free to share it in the comments below.
Resources:
While writing this post, civilians and children in Gaza are being killed in the ongoing genocide. It's important to be informed about what is happening in Palestine and to consider the humanitarian aspects of the situation. Please take the time to research, and understand the events and their impact on palestinian's lives. know more