Dear readers, it’s been a while, but I am back!
Let’s talk about TypeScript.
Nowadays Typescript has become increasingly popular for its type safety and scalability in the JavaScript development. Most important it could also catch potential errors in your code!
An important concept to highlight is that TypeScript code will be compiled into JavaScript code during the build process as TypeScript does not run in the browser.
There are two methods of installing TypeScript:
- Install locally in your project using the following command:
npm install typescript --save-dev
or
yarn add typescript --dev
TypeScript is available as the package on the npm registry or yarn, then you can run the TypeScript compiler using the following command:
npx tsc [file.ts]
After running the command, TypeScript will compile file.ts
into JavaScript file.js
based on the TypeScript compiler's default settings or any custom settings defined in a tsconfig.json
file.
2. Or, install globally on your system:
npm install -g typescript
By installing it globally, you can directly use the tsc
command (without npx
) in your terminal or command prompt to compile TypeScript into JavaScript file.
tsc [file.ts]
When you are writing TypeScript code, you will often encounter with various syntax features that you may not fully understand or that certain aspects feel strange (Yeah that’s how I felt too)!
Before diving into primitive types and functions, let’s review some of these syntax and key concepts.
- Type annotation ( : )
Type annotation :
is primarily used when declaring variables, function arguments or function return types.
let age: number = 10;
function greet(name: string): string {
return `Hello, my name is ${name}.`;
}
2. Optional property ( ? )
Optional property ?
denotes an optional property in an object, it allows a property or parameter to be omitted when the corresponding field is not provided.
type User = {
name: string;
age?: number; // optional property
}
function greet(user: User): string {
if (user?.age !== undefined) {
return `Hello, my name is ${name} and I am ${age} year old.`;
}
return `Hello, my name is ${name}`;
}
3. Non-null assertion ( ! )
Non-null assertion !
is used to assert that the value is not null
or undefined.
function greet(name: User): string | null {
if (name === 'kahmun') {
return `Hello, my name is ${name}`;
}
return null;
}
let name = 'kahmun';
const greeting = greet(name)!; // assert that the return is not null
4. Type assertion ( as )
Type assertion as
is used to tell TypeScript to treat an expression as a specific type if it could not infer the type of the value.
let name: any = 'kahmun' // this variable might hold any type of value
let length = (name as string).length; // let TS know to treat it as string
5. Type union & literal type ( | )
Type union |
allows you to specify that a variable can hold values of multiple different types.
let a: string | number; // variable a can be either a string or a number
a = 'kahmun';
a = 12;
While literal type |
allows you to specify exact values that a variable can hold.
let color: 'red' | 'blue' | 'green';
color = 'red' // valid
color = 'black' // Error: type "black" is not assignable
6. Type intersection ( & )
Type intersection &
is used to combine multiple types into a single type that has all the properties of each type.
type Basic = {
name: string;
age: number;
}
type Contact - {
mobile: string;
homeAddress: string;
}
type User = Basic & Contact;
7. Type generic ( <T> )
Type genetic <T>
allows you to define for reusable function or component that can work with any data type.
// generic function to return array of any type
function arrayItem<T>(array: T[]): T[] {
return array;
}
const colors: string[] = ['red', 'blue', 'black'];
const colorArray = arrayItem(colors);
..
const units: number[] = [1, 3, 4];
const unitArray = arrayItem(units);
Basic Primitive Types
TypeScript supports the same primitive types like JavaScript such as string, boolean, number, null and undefined.
// String
let name: string = 'kahmun';
// Boolean
let isDone: boolean = true;
// Number
let age: number = 22;
let decimal: number = 6.5;
// Null
let data: null = null;
// Undefined
let undefinedValue: undefined = undefined;
Object Type
An object type is defined using curly braces {} to describe the properties.
// Define an object type
type User = {
name: string;
age: number;
email?: string; // optional property
};
// Usage of the User object type
let kahmun: Person = {
name: 'Kah Mun',
age: 32,
email: 'kahmun@gmail.com'
};
let may: Person = {
name: 'May',
age: 40,
}
Another object type with nested properties.
// Define an object type
type Contact = {
mobile: string;
homeAddress: string;
}
type User = {
name: string;
age: number;
email?: string; // optional property
contact: Contact // from Contact type
};
let kahmun: Person = {
name: 'Kah Mun',
age: 32,
contact: {
mobile: '+601234567',
homeAddress: '12, Home Street, 44000, Malaysia',
}
}
Array Type
TypeScript provides robust support for array, too. :D
let colors: string[] = ['red', 'blue', 'black'];
let numbers: number[] = [1, 2, 3];
let mixedArray: (string | number)[] = ['hi', 'I am', 'kahmun', 32];
type User = {
name: string;
age: number;
email?: string; // optional property
};
let people: User[] = [
{name: 'Kah Mun', age: 32},
{name: 'May', age: 40},
];
Or, read only array type to prevent further modification.
let colors: readonly string[] = ['red', 'blue', 'black'];
Function Type
function add(a: number, b: number): number {
return a + b;
}
// we can actually omit the return type as TS is able to infer it
function add(a: number, b: number) {
return a + b;
}
// function with optional parameter
function add(a: number, b: number, c?: number) {
if (c) {
return a + b + c;
}
return a + b;
}
Type vs Interface
In general, we can use whichever we prefer, we use type
to define other type like object and function, but not when using interface
. There are some key differences between type
and interface
, such as:
interface
is limited to define type for object only, whiletype
can create aliases for any type, including object, function, intersection and union types, etc.interface
is able to extend another properties using theextends
keyword. We can use interface when working on a project usingclass
, but most of the time JavaScript doesn’t, thereforetype
is generally used.
Example of type:
// type definition for a function
type AddFunc: (a: number, b: number) => number;
// type alias
type Sum = {
a: number;
b: number:
addFunc: AddFunc
}
let add: Sum = {
a: 1,
b: 2,
addFunc: (a, b) => a + b
};
// merging type
type MultipleFunc: (c: number, d: number) => number;
type Mutiple = {
c: number;
d: number;
multipleFunc: MultipleFunc
}
type Calculate = Sum & Mutiple;
let calculate: Calculate = {
a: 1,
b: 2,
addFunc: (a, b) => a + b,
c: 2,
d: 3,
multipleFunc: (c, d) => c + d,
}
Example of interface:
// interface
interface Appearance {
color: string;
border: string;
}
// Interface for Reactangle extending the Shape interface
interface Rectangle extends Appearance {
width: number;
height: number;
}
function calculateArea(r: Rectangle): number {
return r.width * r.height;
}
let myRectangle: Rectangle = {
color: 'blue',
border: '5px'
width: 10,
height: 5
};
const area = calculateArea(myRectangle);
Type Guard & Type Narrowing
These concepts allow you to narrow down the type of a variable within a certain code block to a more specific type.
Example of type guard:
function isString(value: any): string {
return typeof value === 'string';
}
let a: any = 'hello world';
// execute a string method if x is a string
if (isString(a)) {
console.log(x.toUpperCase());
} else {
console.log('x is not a string');
}
Example of type narrowing:
function add(a: number | string, b: number | string) {
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
}
return `${a} ${b}`;
}
And with that, we’ve reached the end of our TypeScript’s basic adventure. Remember, writing TypeScript is like wearing a seatbelt on your code, whoops!
Until next time, happy TypeScript-ing! 😛