π What is TypeScript?
TypeScript is a strongly typed, object-oriented programming language that builds on JavaScript by adding static types.
β οΈ Limitations of JavaScript
- Dynamically Typed Language: We can put a string or number or array or object on the same variable which isnβt a feasible thing. Also checking the type errors in large-scale apps is very difficult.
let a = 'Nur Alam';
a=[1,2,3]
- JavaScript supports object-oriented programming through prototypes and ES6 classes.
- In JS we find the errors in runtime rather compile time.
- When working on a large application with JS then itβs difficult to maintain a large codebase, it's hard to find bugs, and catch errors only in runtime.
- If we need to convert the code to support old browser then it will be a issue. But typescript can be transpiled into an older version of JS easily.
** Browsers don't natively support TypeScript. We need to convert it to JS
β Why Use TypeScript? (Benefits)
- Supports older browser
- Type safety
- Increase Productivity
- Fewer Bugs and less testing
- TS has all types of JS( Number, String, Boolean, Null, Undefined, Object, Symbol) and has some own types as well (Interface, Void, Array, Tuple, Enum, Union, Intersection).
Drawbacks of TypeScript
- Type Complexities ( Have to define types for small projects)
- Limited Library support (Have to take additional library support sometimes)
- Over-engineering in type design can complicate small projects.
- Migration Challenge (Convert existing JS to TS)
π οΈ Installing and Running TypeScript
Install Typescript: npm i -g typescript
Run Typescript Code:
- Initialize Typescript Config:
tsc --init
- Go to tsconfig.json and change the rootDir and outDir with uncomment to your path. Ex:
"rootDir": "./app/src/", // TS Files
"outDir": "./app/dist/", //Output directory
- Open the terminal and run βtscβ. It will compile ts file to js. You can set compile version in βtargetβ of tsconfig.json. For example:
"target" : "ES5",
***To easily run ts file, we can use ts-node-dev npm package. Hereβs the process:*
//Install
npm i -g ts-node-dev
//Run
ts-node-dev --respawn --transpile-only server.ts
π’ Primitive and Non-Primitive Types
Primitive: number, string, boolean, null, undefined, symbol
Non primitive: Array, Tuple, Object
** In JS, Objects are non-primitive. TS has array and objects both data types. We donβt get data type in TS in runtime, we get it when we compile.
π Implicit vs Explicit Data Typing
When we define type then itβs explicit.
π Basic Data Types with Examples
//string
let firstName: string = 'Nur'
//number
let roll: number = 123
//boolean
let isAdmin: boolean = true
//undefined
let x: undefined = undefined
//null
let y:null = null
//any. Can be any data type. Isn't recommended to use.
let z: any = 'Any'
//Array
let friends: string[] = ['Alice', 'Rachel']
//tuple ->Special type of array which maintains type order
let coordinates: [number, number] = [5,5]
//Object
const user: {
firstName: string;
middleName?: string; //Optional
lastName: string;
} = {
firstName: 'Nur',
lastName: 'Alam'
}
π¦ Object Literals
It defines its own type. In below example company name is fixed so we can define a new type for that.
const user: {
company: 'Google', // Literal Type
firstName: string;
middleName?: string; //Optional
lastName: string;
} = {
company: 'Google',
firstName: 'Nur',
lastName: 'Alam'
}
ποΈ Functions in TypeScript
//Normal Function with types and predefined value
function add(num1: number, num2: number = 10): number {
return num1 + num2;
}
//Arrow Function
const add = (num1: number, num2: number): number => num1 + num2;
//Method -> A function inside JS Object
const user = {
name: "Nur",
balance: 0,
addBalance(balance: number): number {
return this.balance + balance;
},
};
//Callback Function - A callback function is a function passed as an argument to another function and is executed later within that function.
//Here a arrow function is passed in map function
const num: number[] = [1, 2, 3];
const doubleNum: number[] = num.map((elem: number): number => elem * 2);
π Spread & Rest Operators
ββSpread operator expands elements, while the rest operator collects arguments into an array.
//Spread Operator
const arr1: number[] = [1, 2, 3];
const arr2: number[] = [4, 5, 6];
const combineArr: number[] = [...arr1, ...arr2];
//Rest Operator -> Used to collect multiple arguments into a single array.
const employee = (...employee: string[]) => {
employee.forEach((em: string) => console.log(`Onboard ${em}`));
};
employee("Nur", "Abul", "Rimon");
ποΈ Destructuring in TS:
//Object Destructuring
const user = {
id: 123,
name: {
firstName: 'Nur',
lastName: 'Alam',
}
}
//Destructuring id as userID ( Name Alias) and firstName
const {id: userID, name: { firstName }} = user;
//Array Destructure
const friends = ["Joy", "Akash", "Karim", "Latif", "Opu" ]
//Destructuring Karim as bestfriend and latif, opu in rest
const [,,bestFriend, ...rest] = friends
π Type Alias
//Type Alias in object
type User = {
firstName: string;
middleName?: string; //Optional
lastName: string;
}
const user1: User = {
firstName: 'Nur',
lastName: 'Alam'
}
//Type Alias in Function
type Add = (num1: number, num2: number) => number
const add: Add = (num1, num2) => num1+num2;
π Union, Intersection, Nullish Coalescing Operator
// Ternary Operator
const hasPassed = mark >=40 ? "Passed" : "Failed";
//Union
const user = User1 | User2 // Can be either of User type
//Intersection
const user = User1 & User2 // Combination of both the type and will contain all field
// Nullish Coalesing Operator
// Used when need to make decision based on null or undefined
const isAdmin = null;
const userType = isAdmin ?? "Normal User";
//Optional Chaining
const isPassed = student?.marks ?? "Didn't attend exam"
π« Never, Unknown, Nullable Types
never is used for functions that never return or reach the end.
function throwError(message: string): never {
throw new Error(message);
}
unknown represents a value with an unknown type and requires type checking before use.
let data: unknown = "Hello";
if (typeof data === "string") {
console.log(data.toUpperCase());
}
Nullable types (null and undefined) allow variables to have no value or be unassigned.
let name: string | null = null;
let age: number | undefined;
π§ Type Assertion & Type Narrowing
Type Assertion tells TypeScript to treat a value as a specific type.
let value: unknown = "Hello, TypeScript!";
let strLength: number = (value as string).length;
console.log(strLength); // Output: 18
Type Alias vs Interface:
The interface is primarily used to define the structure of objects and is extendable using the extends keyword, making it ideal for object-oriented designs. It also supports declaration merging, allowing multiple declarations of the same interface to automatically combine.
On the other hand, type is more flexible and can define primitives, unions, tuples, and object types but does not support declaration merging. It uses the intersection operator (&) to combine types. For example, using an interface:
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
salary: number;
}
Whereas with a type alias:
type PersonType = { name: string; age: number; };
type EmployeeType = PersonType & { salary: number; };
Merging
interface User {
name: string;
}
interface User {
age: number;
}
// Result: { name: string; age: number; }
π οΈ Generics
Generics in TypeScript allow us to create reusable components that can work with a variety of data types while maintaining type safety. Instead of specifying a fixed type, generics use type parameters that are specified when the function, class, or interface is used.
//Generic Array
type GenericArray<T> = Array<T>;
//Same as GenericArray[number]
const roll: GenericArray<number> = [1, 2, 3];
//Generic Object
const user: GenericArray<{ name: string, age: number}> = [
{
name: "Nur",
age: 25
}
]
//Generic Tuple
type GenericTuple<X,Y> = [X,Y]
const user: GenericTuple<string, string> = ["Mr. X", "Admin"]
//Generic with interface
interface ApiResponse<T> {
status: number;
data: T;
}
const userResponse: ApiResponse<{ name: string; age: number }> = {
status: 200,
data: { name: "Alice", age: 25 },
};
const productResponse: ApiResponse<string[]> = {
status: 200,
data: ["Laptop", "Phone"],
};
//Generic in Function
const createGenericArr = <T>(param: T): T[] =>{
return [param];
}
const result = createGenericArr<string>("Hello");
//Generic in tuple
const genericTuple =<T,Q>(param1: T, param2: Q): [T,Q]=>{
return [param1, param2];
}
π§ Constraints:
Constraints in TypeScript limit the types that can be used in generics to ensure type safety.
function printLength<T extends { length: number }>(item: T) {
console.log(item.length);
}
printLength("Hello"); // β
Works (string has length)
printLength([1, 2, 3]); // β
Works (array has length)
// printLength(123); // β Error (number has no length)
π keyof Constraint
Limits a generic type to the keys of another type.
interface Person {
name: string;
age: number;
}
function getValue<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const person: Person = { name: "Alice", age: 25 };
console.log(getValue(person, "name")); // β
Output: Alice
// getValue(person, "height"); // β Error: "height" is not a key of Person
β‘ Conditional Types:
Conditional types allow you to create types that depend on a condition.
type IsString<T> = T extends string ? "Yes" : "No";
type Test1 = IsString<string>; // "Yes"
type Test2 = IsString<number>; // "No"
Mapped Types:
Mapped types allow you to transform existing types by looping over their properties.
type Person = {
name: string;
age: number;
};
// Make all properties optional
type PartialPerson = {
[K in keyof Person]?: Person[K];
};
const person: PartialPerson = { name: "Alice" }; // `age` is optional
π οΈ Utility Types
- Pick β Select specific properties from a type
interface Person {
name: string;
age: number;
address: string;
}
type NameAndAge = Pick<Person, "name" | "age">;
const person: NameAndAge = { name: "Alice", age: 25 };
- Omit β Exclude specific properties from a type
type WithoutAddress = Omit<Person, "address">;
const personWithoutAddress: WithoutAddress = { name: "Bob", age: 30 };
- Required β Make all properties mandatory
interface Product {
id: number;
description?: string;
}
type RequiredProduct = Required<Product>;
const product: RequiredProduct = { id: 1, description: "New product" };
- Readonly β Make all properties immutable
interface Car {
model: string;
year: number;
}
const car: Readonly<Car> = { model: "Tesla", year: 2023 };
// car.model = "BMW"; // β Error: Cannot assign to 'model' because it is a read-only property
- Record β Create an object type with specified keys and value types
type UserRole = "admin" | "user" | "guest";
const roles: Record<UserRole, string> = {
admin: "Full Access",
user: "Limited Access",
guest: "Read-Only Access",
};
- Partial β Make all properties optional
interface Profile {
username: string;
email: string;
}
type OptionalProfile = Partial<Profile>;
const userProfile: OptionalProfile = { username: "Nur" }; // `email` is optional
Enum:
Enums allow us to define a set of named constants. It makes code more readable and manageable when dealing with constant values and
enforces valid inputs over plain strings or numbers.
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
let move: Direction = Direction.Left;
console.log(move); // Output: "LEFT"
Template Literal Types:
Template Literal Types build complex types using string literals and union types.
type HttpMethod = "GET" | "POST";
type ApiRoute = "/users" | "/products";
type Endpoint = `${HttpMethod} ${ApiRoute}`;
const getUser: Endpoint = "GET /users"; // β
const invalid: Endpoint = "DELETE /users"; // β Error
Conclusion
TypeScript offers powerful tools for building scalable and robust applications. It enhances JavaScript with static typing, better tooling, and modern features.
Start using TypeScript today to write cleaner, safer, and more efficient code!
Got questions or feedback? Drop a comment below! π
Follow me to learn OOP in Typescript.
Happy Coding! π
Top comments (0)