_
**
Module-1: Explore basic types of typescript
**
1-2 install typescript and node version manager in **ubuntu **
_
To install TypeScript and Node Version Manager (nvm) on your Ubuntu Linux system, you can follow these steps:
1. Install Node Version Manager (nvm):
First, open your terminal and run the following commands to install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
This command will download and execute the nvm installation script.
After the installation is complete, close and reopen your terminal, or run:
source ~/.bashrc
This will load nvm into your current shell session.
. Install Node.js and TypeScript:
Now that nvm is installed, you can use it to install Node.js and TypeScript. Here's how to install the latest LTS version of Node.js and TypeScript:
nvm install --lts
This command installs the latest LTS (Long Term Support) version of Node.js. Once Node.js is installed, you can install TypeScript using npm (Node Package Manager), which comes bundled with Node.js:
npm install -g typescript
This command installs TypeScript globally on your system.
3. Verify the installations:
You can verify that both Node.js and TypeScript have been installed by checking their versions:
node -v
npm -v
tsc -v
This should display the version numbers of Node.js, npm, and TypeScript.
That's it! You've successfully installed Node.js and TypeScript on your Ubuntu Linux system using nvm. You can now start developing TypeScript applications with Node.js.
If you want to switch to Node.js version 14 for your previous projects using Node Version Manager (nvm), you can follow these steps:
1. Check available Node.js versions:
To see the list of Node.js versions available for installation, you can use the following command:
nvm ls-remote
This will list all the available Node.js versions. You can look for version 14 in the list.
2. Install Node.js version 14:
To install Node.js version 14, use the following command, replacing "14" with the version you want:
nvm install 14
This will download and install Node.js version 14.
3. Set Node.js version 14 as the default:
To set Node.js version 14 as the default version for your projects, use the following command:
nvm use 14
This will switch your current shell session to use Node.js version 14. If you want to make it the default for all new shell sessions, you can run:
nvm alias default 14
Now, Node.js version 14 is the default version, and you can use it for your previous projects.
4. Verify the Node.js version:
You can verify that Node.js version 14 is in use by running:
node -v
This should display the version of Node.js, which should be 14.x.x if the installation was successful.
That's it! You've now switched to Node.js version 14 using nvm, and you can use it for your previous projects.
To switch back to Node.js version 20.9.0 or any other version you were using, you can use Node Version Manager (nvm). Here are the steps to switch to version 20.9.0:
- List the available Node.js versions to see which versions are installed and available for use:
nvm ls
This will list the installed Node.js versions, and the currently active version will be indicated with an arrow.
- To switch to Node.js version 20.9.0, use the following command, replacing "20.9.0" with the specific version you want:
nvm use 20.9.0
This command will set the active Node.js version to 20.9.0.
- You can verify that you've switched to Node.js version 20.9.0 by running:
node -v
This should display the version number, which should be 20.9.0 if the switch was successful.
Now you are using Node.js version 20.9.0 for your projects. If you want to make this version the default for all new shell sessions, you can run:
nvm alias default 20.9.0
This will set version 20.9.0 as the default for new sessions.
You can use these commands to switch between different Node.js versions whenever you need to work on specific projects that require different Node.js versions.
============================================================
1-3 Write your first typescript program
Typescript config file
: tsc --init
then we ill get a tsconfig.json file, then we will edit it:
- search rootDir; then write typescritp file location in this rootDir
- search outDir, write path of my typescript file will store in which location.
some extra package. to run typescript code directly
1. Install ts-node-dev globally (recommended):
npm install -g ts-node-dev
2. Use npx (without installing globally):
ts-node-dev --respawn --transpile-only filelocation/filename.ts
npx ts-node-dev --respawn --transpile-only ./module1/src/index.ts
1-4 Basic data types
Certainly! Here are examples of various data types in TypeScript:
- Integer (int):
const age: number = 30;
- Floating-Point (float and double):
const pi: number = 3.14159;
- Boolean (bool):
const isTrue: boolean = true;
- Character (char):
In TypeScript, characters are represented as single-character strings:
const firstLetter: string = "A";
- String:
const greeting: string = "Hello, TypeScript!";
- Null:
const nullValue: null = null;
- Undefined (or None):
let undefinedValue: undefined;
- Void:
Functions with no return value have a void type:
function sayHello(): void {
console.log("Hello, world!");
}
- Symbol:
const uniqueSymbol: symbol = Symbol("description");
-
Byte:
TypeScript doesn't have a specific byte data type, but you can work with bytes using
numberorUint8Array. -
Date and Time:
TypeScript can work with date and time using JavaScript's
Dateobject:
const currentDate: Date = new Date(); -
BigInteger and BigDecimal:
TypeScript supports large integers through the
BigInttype:
const bigIntValue: bigint = 1234567890123456789012345678901234567890n; -
Array:
Arrays in TypeScript can hold multiple values of the same data type:
const numbers: number[] = [1, 2, 3, 4, 5]; -
Tuple:
Tuples allow you to specify the types and order of elements in a fixed-size collection:
const person: [string, number] = ["Alice", 30]; -
Enum:
Enums define a set of named constant values:
enum Color { Red, Green, Blue, } const selectedColor: Color = Color.Red; -
Any:
The
anytype is used when you want to opt out of TypeScript's type checking or when dealing with dynamic types:
let dynamicValue: any = 42; dynamicValue = "Hello, World!"; -
Union Types:
Union types allow variables to hold values of multiple types:
let mixedValue: number | string = 42; mixedValue = "Hello, World!"; -
Intersection Types:
Intersection types combine multiple types into one, allowing access to properties of each type:
type Employee = { name: string; role: string }; type Manager = { reports: number }; type ManagerEmployee = Employee & Manager; const manager: ManagerEmployee = { name: "Alice", role: "Manager", reports: 5 }; -
Object:
The
objecttype represents non-primitive values, such as functions, arrays, and objects:
const user: object = { name: "Alice", age: 30 }; -
Function:
Functions in TypeScript can be defined with specific parameter and return types:
const add: (x: number, y: number) => number = (x, y) => x + y;
These examples cover a wide range of basic data types and type annotations available in TypeScript. Each type has its own specific use cases, and TypeScript's strong type system helps catch type-related errors and improve code quality.
In TypeScript, you can work with various basic data types, including:
These are the basic data types in TypeScript. Additionally, TypeScript supports more advanced types such as object, any, void, null, and undefined, as well as user-defined types like enum, tuple, and union types to handle a wide range of data in a strongly typed manner.
- Number: Used for numeric values (integers and floating-point numbers).
let age: number = 30;
let pi: number = 3.14;
- String: Used for text and character data.
let name: string = "John";
let message: string = 'Hello, TypeScript!';
- Boolean: Represents true or false values.
let isStudent: boolean = true;
let isWorking: boolean = false;
- Array: Used to store collections of values, and you can specify the type of elements it contains.
let numbers: number[] = [1, 2, 3, 4, 5];
let fruits: string[] = ["apple", "banana", "cherry"];
1-5 Object , Optional and Literal
Here are examples of TypeScript data types and features related to objects, optional properties, and literals:
- Object Type:
TypeScript allows you to define object types to represent structured data with specific properties and their types.
const person: { name: string; age: number } = {
name: "Alice",
age: 30,
};
- Optional Properties:
You can specify optional properties in object types using the ? symbol.
const user: { name: string; age?: number } = {
name: "Bob",
// Age is optional, so it can be omitted
};
- Literal Types:
TypeScript allows you to define literal types where a variable can only have a specific, literal value.
const status: "active" | "inactive" = "active";
- Object with Optional and Literal Properties:
You can combine object types, optional properties, and literal types.
const person: { name: string; age?: number; status: "active" | "inactive" } = {
name: "Charlie",
status: "active",
};
- Type Alias:
You can create type aliases for object types to make your code more readable.
type Person = { name: string; age?: number };
const user: Person = {
name: "David",
// Age is optional
};
- Interface:
Interfaces are similar to type aliases but are often used when defining the shape of objects.
interface Product {
name: string;
price: number;
}
const item: Product = {
name: "Widget",
price: 10.99,
};
- Record Type:
You can use the Record type to define object types with specific keys and their associated value types.
const phonebook: Record<string, string> = {
Alice: "555-1234",
Bob: "555-5678",
};
1-6 Function in typescript
1-7 Spread and Rest Operator
Certainly! Here are examples of the spread and rest operators in TypeScript:
- Spread Operator:
The spread operator, denoted by ..., is used to split an array or object into individual elements. It can be used to create new arrays or objects by combining existing ones.
-
Array Spread:
const arr1: number[] = [1, 2, 3]; const arr2: number[] = [4, 5, 6]; const combinedArray: number[] = [...arr1, ...arr2]; -
Object Spread:
const person = { name: "Alice", age: 30 }; const additionalInfo = { city: "Wonderland" }; const combinedPerson = { ...person, ...additionalInfo };
- Rest Operator:
The rest operator, also denoted by ..., is used to collect multiple values into an array. It is often used in function parameters to handle a variable number of arguments.
-
Rest Parameters in Functions:
function sum(...numbers: number[]): number { return numbers.reduce((total, num) => total + num, 0); } const result1: number = sum(1, 2, 3, 4, 5); // Result: 15 -
Rest Elements in Arrays:
const [first, second, ...rest] = [1, 2, 3, 4, 5]; console.log(first); // 1 console.log(second); // 2 console.log(rest); // [3, 4, 5]
{
typescript can acess all function globally. so we can use {bracket} in a ts file, then wont access same function globally.
}
1-8 Destructuring in typescript
Destructuring is a powerful feature in TypeScript that allows you to extract values from arrays and objects and assign them to variables. Here are examples of destructuring in TypeScript:
- Array Destructuring:
You can destructure arrays to extract individual values and assign them to variables:
const numbers: number[] = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
- Object Destructuring:
Object destructuring allows you to extract properties from objects and assign them to variables with the same name:
const person = {
name: "Alice",
age: 30,
city: "Wonderland",
};
const { name, age } = person;
console.log(name); // "Alice"
console.log(age); // 30
- Renaming Variables in Object Destructuring:
You can also rename variables while destructuring objects:
const person = {
name: "Bob",
age: 25,
};
const { name: fullName, age: years } = person;
console.log(fullName); // "Bob"
console.log(years); // 25
- Default Values in Object Destructuring:
You can provide default values for object properties that might not exist:
const person = {
name: "Charlie",
};
const { name, age = 30 } = person;
console.log(name); // "Charlie"
console.log(age); // 30
- Nested Destructuring:
Destructuring can also be used with nested objects:
const student = {
name: "David",
details: {
age: 21,
major: "Computer Science",
},
};
const { name, details: { age, major } } = student;
console.log(name); // "David"
console.log(age); // 21
console.log(major); // "Computer Science"
...rest
1-9 Type alias in typescript
1-10 Union and Intersection types
1-11 Ternary, optional chaining & nullish coalescing operator
1. nullish operator(??) its works for Null and undefined. not for "" .

1-12 Never,unknown and nullable type
Certainly! Here are examples of TypeScript data types and features related to never, unknown, and nullable types:
-
neverType:
The never type represents values that never occur. It is often used to indicate that a function will never return normally or that a variable cannot have a value.
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {
// Infinite loop
}
}
-
unknownType:
The unknown type is a type-safe counterpart to any. Variables of type unknown can hold values of any type, but you must perform type checks before using them.
let userInput: unknown;
let username: string;
userInput = "Alice";
if (typeof userInput === "string") {
username = userInput;
}
- Nullable Types:
TypeScript allows you to make a type nullable using the null and undefined values.
let numberOrNull: number | null = null;
let stringOrUndefined: string | undefined = "Hello";
-
Using
nullandundefinedTogether:
You can create a type that allows both null and undefined values.
let value: number | null | undefined = null;
-
Type Assertion for
unknown:
When working with unknown, you can use type assertions to tell TypeScript to treat a value as a specific type.
let userInput: unknown = "Bob";
let username: string = userInput as string;
- Strict Null Checks:
TypeScript's strict null checks prevent variables from being used before being checked for null or undefined, reducing the risk of runtime errors.
let possiblyNull: string | null = null;
// Error: Object is possibly 'null'.
console.log(possiblyNull.length);
- Non-Nullable Assertion:
You can use the non-nullable assertion operator ! to tell TypeScript that a value is not null or undefined.
let definitelyNotNull: string | null = "Carol";
let length: number = definitelyNotNull!.length; // No error
These examples showcase TypeScript's never, unknown, and nullable types, which provide more control over types, safer code, and improved handling of optional and potentially missing values.
- Nullable type
- unknown type
3.Never
========================================================================
*## Module 2: Explore advance types of typescript
*
2-1: Type assertion / type narrowing
=> as use korle typescript sure hoy je ami je type a declare korbo shei type er e hobe.
{
//
// type assertion
let anything: any;
anything = "Next Level Web Development";
anything = 222;
// (anything as number).
const kgToGm = (value: string | number): string | number | undefined => {
if (typeof value === "string") {
const convertedValue = parseFloat(value) * 1000;
return `The converted value is : ${convertedValue}`;
}
if (typeof value === "number") {
return value * 1000;
}
};
const result1 = kgToGm(1000) as number;
const result2 = kgToGm("1000");
type CustomError = {
message: string;
};
try {
} catch (error) {
console.log((error as CustomError).message);
}
//
}
2-2: Interface, type vs interface
=> type ke interface a extend and interface ke type a extend kora jabe.
// interface
type User1 = {
name: string;
age: number;
};
type UserWithRole1 = User1 & { role: string };
const user1: UserWithRole1 = {
name: "Persian",
age: 100,
role: "manager",
};
interface User2 {
name: string;
age: number;
}
interface UserWithRole2 extends User2 {
role: string;
}
const user1: UserWithRole2 = {
name: "Persian",
age: 100,
role: "manager",
};
type rollNumber = number;
// js --> object , array-> object function -> object
type Roll1 = number[];
const rollNumber1: Roll2 = [1,2,3]
interface Roll2 {
[index : number ] : number
}
const rollNumber1: Roll2 = [1,2,3]
0 1 2 --> number type
type Add1 = (num1: number,num2:number)=> number
const add: Add1 = (num1 , num2 )=> num1+num2
interface Add2 {
(num1: number,num2:number) : number
}
const add: Add2 = (num1 , num2 )=> num1+num2
2-3: Introduction to generics
{
// generic type
type GenericArray<T> = Array<T>;
// const rollNumbers: number[] = [3, 6, 8];
const rollNumbers: GenericArray<number> = [3, 6, 8];
// const mentors: string[] = ["Mr. X", "Mr. Y", "Mr. Z"];
const mentors: GenericArray<string> = ["Mr. X", "Mr. Y", "Mr. Z"];
// const boolArray: boolean[] = [true, false, true];
const boolArray: GenericArray<boolean> = [true, false, true];
interface User {
name: string;
age: number;
}
const user: GenericArray<User> = [
{
name: "Mezba",
age: 100,
},
{
name: "Jhankar Mahbub",
age: 110,
},
];
const add = (x: number, y: number) => x + y;
add(30, 20);
//generic tuple
type GenericTuple<X, Y> = [X, Y];
const manush: GenericTuple<string, string> = ["Mr. X", "Mr. Y"];
const UserWithID: GenericTuple<number, { name: string; email: string }> = [
1234,
{ name: "persian", email: "a@gmail.com" },
];
}
// Generic tuple
type GenericTuple<X, Y> = [X, Y];
const manush: GenericTuple<string, string> = ["Mr. X", "Mr. Y"];
const UserWithID: GenericTuple<number, { name: string; email: string }> = [1234, { name: "persian", email: "a@gmail.com" }];
console.log(manush); // Output: ["Mr. X", "Mr. Y"]
console.log(UserWithID); // Output: [1234, { name: "persian", email: "a@gmail.com" }]
=================
// Non-generic tuple types
type StringTuple = [string, string];
type UserWithIDTuple = [number, { name: string; email: string }];
const manush: StringTuple = ["Mr. X", "Mr. Y"];
const UserWithID: UserWithIDTuple = [1234, { name: "persian", email: "a@gmail.com" }];
console.log(manush); // Output: ["Mr. X", "Mr. Y"]
console.log(UserWithID); // Output: [1234, { name: "persian", email: "a@gmail.com" }]
2-4: Generic with Interface
{
// intercae - generic
interface Developer<T, X = null> {
name: string;
computer: {
brand: string;
model: string;
releaseYear: number;
};
smartWatch: T;
bike?: X;
}
type EmilabWatch = {
brand: string;
model: string;
display: string;
};
const poorDeveloper: Developer<EmilabWatch> = {
name: "Persian",
computer: {
brand: "Asus",
model: "X-255UR",
releaseYear: 2013,
},
smartWatch: {
brand: "Emilab",
model: "kw66",
display: "OLED",
},
};
interface AppleWatch {
brand: string;
model: string;
heartTrack: boolean;
sleepTrack: boolean;
}
interface YamahaBike {
model: string;
engineCapacity: string;
}
const richDeveloper: Developer<AppleWatch, YamahaBike> = {
name: "Rich Dev",
computer: {
brand: "HP",
model: "X-25UR",
releaseYear: 2018,
},
smartWatch: {
brand: "Apple Watch",
model: "Something",
heartTrack: true,
sleepTrack: true,
},
bike: {
model: "Yamaha",
engineCapacity: "100cc",
},
};
//
}
2-5: Function with generics
{
// function with generics
const createArray = (param: string): string[] => {
return [param];
};
const createArrayWithGeneric = <T>(param: T): T[] => {
return [param];
};
const res1 = createArray("Bangladesh");
const resGeneric = createArrayWithGeneric<string>("Bangladesh");
type User = { id: number; name: string };
const resGenericObj = createArrayWithGeneric<User>({
id: 222,
name: "Mr. Pashan",
});
const createArrayWithTuple = <T, Q>(param1: T, param2: Q): [T, Q] => {
return [param1, param2];
};
const res10 = createArrayWithTuple<string, number>("Bangladesh", 222);
const res11 = createArrayWithTuple<string, { name: string }>("Bangladesh", {
name: "Asia",
});
const addCourseToStudent = <T>(student: T) => {
const course = "Next Level Web Development";
return {
...student,
course,
};
};
const student1 = addCourseToStudent({
name: "Mr X",
email: "x@gmail.com",
devType: "NLWD",
});
const student2 = addCourseToStudent({
name: "Mr Y",
email: "y@gmail.com",
hasWatch: "Apple Watch",
});
//
}
2-6: Constraints in typescript
{
// constraints
const addCourseToStudent = <
T extends { id: number; name: string; email: string }
>(
student: T
) => {
const course = "Next Level Web Development";
return {
...student,
course,
};
};
const student3 = addCourseToStudent({
id: 44,
name: "Mr. Z",
email: "z@gmail.com",
emni: "emni",
});
const student1 = addCourseToStudent<{
id: number;
name: string;
email: string;
devType: string;
}>({
id: 222,
name: "Mr X",
email: "x@gmail.com",
devType: "NLWD",
});
const student2 = addCourseToStudent({
id: 333,
name: "Mr Y",
email: "y@gmail.com",
hasWatch: "Apple Watch",
});
//
}
2-7: Constraint using key of
The keyof operator is useful in TypeScript for several reasons:
Type Safety: It enforces type safety by allowing you to restrict the set of possible keys that can be used when accessing properties of an object. This helps catch potential runtime errors at compile time.
Code Completion and Documentation: It enhances the development experience by providing code editors with information about the available keys, enabling better code completion and documentation.
Improved Refactoring: When you use
keyof, if you rename a property in the object type, your code editor can help you identify and update all the places where that property is accessed, ensuring that your refactoring is more reliable.Reduced Error Handling: By limiting the possible keys, you can reduce the need for extensive error handling because TypeScript can catch invalid key accesses at compile time. This makes your code more robust and less prone to runtime errors.
Here's an example to illustrate the benefits:
type User = {
name: string;
email: string;
};
function getUserProperty<T, K extends keyof T>(user: T, key: K): T[K] {
return user[key];
}
const user: User = {
name: "Alice",
email: "alice@example.com",
};
const name: string = getUserProperty(user, "name"); // Valid
const invalidKey = getUserProperty(user, "age"); // Error: Argument of type '"age"' is not assignable to parameter of type '"name" | "email"'.
In the example above, using keyof with the getUserProperty function ensures that only valid keys (in this case, "name" or "email") can be used to access properties of the User object. This helps catch potential errors during development and provides a better development experience.
Overall, the keyof operator is a valuable tool for enhancing the type safety and maintainability of your TypeScript code, especially when working with objects and their properties.
2-8: Asynchronous typescript & promise
{
// promise
type Todo = {
id: number;
userId: number;
title: string;
completed: boolean;
};
const getTodo = async (): Promise<Todo> => {
const response = await fetch(
"https://jsonplaceholder.typicode.com/todos/1"
);
const data = await response.json();
return data;
// console.log(data);
};
getTodo();
type Something = { something: string };
// simulate
const createPromise = (): Promise<Something> => {
return new Promise<Something>((resolve, reject) => {
const data: Something = { something: "something" };
if (data) {
resolve(data);
} else {
reject("failed to load data");
}
});
};
// calling create promise function
const showData = async (): Promise<Something> => {
const data: Something = await createPromise();
return data;
// console.log(data);
};
showData();
//
}
2-9: Conditional types
{
//conditional type
type a1 = number;
type b1 = string;
type x = a1 extends null ? true : false; // conditional type
type y = a1 extends null ? true : b1 extends undefined ? undefined : any;
type Sheikh = {
bike: string;
car: string;
ship: string;
plane: string;
};
//keyof Sheikh "bike" | "car" | "ship"
// car ase kina / bike ase kina / ship kina / tractor ase kina
type CheckVehicle<T> = T extends keyof Sheikh ? true : false;
type HasPlane = CheckVehicle<"plane">;
//
}
2-10: Mapped types
type AreaString<T> = {
[key in keyof T]: T[key];
};
{
// mapped types
const arrOfNumbers: number[] = [1, 4, 5];
// const arrOfStrings : string[] = ['1','4','5']
const arrOfStrings: string[] = arrOfNumbers.map((number) =>
number.toString()
);
console.log(arrOfStrings);
type AreaNumber = {
height: number;
width: number;
};
type Height = AreaNumber["height"]; // look up type
// type AreaString = {
// height: string;
// width: string
// }
// keyof AreaNumber => "height"|"width"
// T => {height:string;width:number}
// key => T["width"]
type AreaString<T> = {
[key in keyof T]: T[key];
};
const area1: AreaString<{ height: string; width: number }> = {
height: "100",
width: 50,
};
//
}
// T => {height:string;width:number}
// key => T["width"]
type AreaString<T> = {
[key in keyof T]: T[key];
};
const area1: AreaString<{ height: string; width: number }> = {
height: "100",
width: 50,
};
2-11 Utility types
Certainly, let's go through some examples of TypeScript utility types:
-
Partial<T>: Makes all properties of a typeToptional.
Certainly, here's a more detailed example of how to use the Partial<T> utility type in TypeScript:
// Define a type for a user with multiple properties
type User = {
id: number;
username: string;
email: string;
age: number;
};
// Create an object of the User type
const completeUser: User = {
id: 1,
username: "john_doe",
email: "john@example.com",
age: 30,
};
// Use the Partial utility type to make all properties optional
type PartialUser = Partial<User>;
// Create an object of the PartialUser type
const partialUser: PartialUser = {};
// Assign values to the optional properties
partialUser.id = 2; // Valid
partialUser.username = "jane_doe"; // Valid
// Attempting to add properties not present in the original User type is also valid
partialUser.country = "USA"; // Valid
// You can also create partial users with some properties while leaving others undefined
const partialUserWithAge: PartialUser = { age: 25 };
// Merge a partial user with a complete user
const mergedUser: User = { ...completeUser, ...partialUserWithAge };
console.log(mergedUser);
In this example:
We start with a
Usertype representing a user object with properties likeid,username,email, andage.We create a complete user object
completeUserwith all properties defined.We use the
Partial<User>utility type to create a new typePartialUserwhere all properties of theUsertype are optional.We create a partial user object
partialUserof typePartialUserwith no properties defined initially.We assign values to some optional properties of
partialUser, demonstrating that these properties can be assigned as needed.We also show that it's valid to add properties to a partial user that were not present in the original
Usertype, such as thecountryproperty.We create another partial user
partialUserWithAgewith theageproperty defined.Finally, we merge a complete user (
completeUser) with a partial user with anageproperty (partialUserWithAge) to create a new user object (mergedUser). This showcases how you can combine complete and partial objects to get a merged result.
-
Required<T>: Makes all properties of a typeTrequired. Certainly, here's an example of theRequired<T>utility type in TypeScript:
// Define a type for a User with optional properties
type User = {
id?: number;
username?: string;
email?: string;
age?: number;
};
// Use the Required utility type to make all properties required
type RequiredUser = Required<User>;
// Create an object of type RequiredUser
const user: RequiredUser = {
id: 1,
username: "john_doe",
email: "john@example.com",
age: 30,
};
// Attempting to create an object with missing properties results in a type error
// const incompleteUser: RequiredUser = {
// id: 2,
// username: "jane_doe",
// age: 28,
// };
In this example:
We have a type
Userwith optional properties, indicated by the?after each property name.We use the
Required<T>utility type to create a new typeRequiredUserwhere all properties are required.We create an object
userof typeRequiredUserwith all properties present, which is valid.Attempting to create an object
incompleteUserof typeRequiredUserwith missing properties results in a TypeScript type error, enforcing that all properties are required for objects of this type.
-
Readonly<T>: Makes all properties of a typeTread-only.
Certainly, here's an example of the Readonly<T> utility type in TypeScript:
type Person = {
name: string;
age: number;
};
type ReadonlyPerson = Readonly<Person>;
const person: ReadonlyPerson = {
name: "Alice",
age: 30,
};
// Attempting to modify properties will result in type errors
person.name = "Bob"; // Error: Cannot assign to 'name' because it is a read-only property.
person.age = 35; // Error: Cannot assign to 'age' because it is a read-only property.
In this example:
We have a type
Personrepresenting a person with propertiesnameandage.We use the
Readonly<T>utility type to create a new typeReadonlyPerson, which makes all properties ofPersonread-only.We create an object
personof typeReadonlyPerson. Attempting to modify any of its properties, such asnameandage, results in TypeScript type errors. This ensures that the object remains immutable and read-only once it's defined.
-
Record<K, T>: Creates an object type with keys of typeKand values of typeT.
Certainly, here's an example of how to use the Record<K, T> utility type in TypeScript:
// Define a type for a shopping cart item with a product ID and quantity
type CartItem = {
productId: number;
quantity: number;
};
// Create a type using Record<K, T> to represent a shopping cart with product IDs as keys and CartItem objects as values
type ShoppingCart = Record<string, CartItem>;
// Create a shopping cart with some items
const shoppingCart: ShoppingCart = {
"product-1": { productId: 1, quantity: 3 },
"product-2": { productId: 2, quantity: 2 },
};
// Add a new item to the shopping cart
shoppingCart["product-3"] = { productId: 3, quantity: 1 };
// Access and update items in the shopping cart
const item1 = shoppingCart["product-1"];
item1.quantity = 4;
// Attempting to add an item with an incorrect key type results in a type error
// shoppingCart[123] = { productId: 4, quantity: 2 }; // Error: Property '123' does not exist on type 'ShoppingCart'.
In this example:
We define a type
CartItemto represent an item in a shopping cart, which includes aproductIdand aquantity.We use the
Record<K, T>utility type to create a typeShoppingCart, which represents a shopping cart with keys of typestring(product IDs) and values of typeCartItem.We create a
shoppingCartobject with some items, where each item is associated with a product ID (string key) and aCartItemvalue.We can add new items, access existing items, and update the quantities for items in the shopping cart.
Attempting to add an item with an incorrect key type (e.g., a number) results in a TypeScript type error, ensuring that only valid keys are allowed in the shopping cart.
-
Pick<T, K>: Selects specific properties from a typeT.
Certainly! Here's an example of how to use the Pick<T, K> utility type in TypeScript:
// Define a type for a User with various properties
type User = {
id: number;
username: string;
email: string;
age: number;
};
// Use the Pick utility type to select specific properties from the User type
type UserIdentity = Pick<User, "id" | "username">;
// Create an object of type UserIdentity
const user: UserIdentity = {
id: 1,
username: "john_doe",
};
// Attempting to add properties other than "id" and "username" will result in a type error
// user.email = "john@example.com"; // Error: Property 'email' does not exist on type 'UserIdentity'.
// user.age = 30; // Error: Property 'age' does not exist on type 'UserIdentity'.
In this example:
We have a type
Userrepresenting a user object with properties likeid,username,email, andage.We use the
Pickutility type to create a new typeUserIdentityby selecting specific properties"id"and"username"from theUsertype.We then create an object
userof typeUserIdentity, which only allows properties"id"and"username". Attempting to assign or access properties other than the selected ones will result in TypeScript type errors, ensuring type safety.
-
Omit<T, K>: Excludes specific properties from a typeT.
Certainly, here's an example of how to use the Omit utility type in TypeScript:
// Define a type for a User with various properties
type User = {
id: number;
username: string;
email: string;
age: number;
};
// Use the Omit utility type to create a new type excluding the "email" property
type UserWithoutEmail = Omit<User, "email">;
// Create an object of type UserWithoutEmail
const user: UserWithoutEmail = {
id: 1,
username: "john_doe",
age: 30,
};
// Attempting to add the "email" property will result in a type error
// user.email = "john@example.com"; // Error: Property 'email' does not exist on type 'UserWithoutEmail'.
In this example:
We have a type
Userrepresenting a user object with properties likeid,username,email, andage.We use the
Omitutility type to create a new typeUserWithoutEmailby excluding the property"email"from theUsertype.We then create an object
userof typeUserWithoutEmail, which does not allow the"email"property. Attempting to assign the"email"property to this object will result in a TypeScript type error, ensuring that the property is excluded from the type.
-
Exclude<T, U>: Excludes values in typeUfrom typeT.
Certainly! Here's an example of how to use the Exclude<T, U> utility type in TypeScript:
type AllColors = "Red" | "Green" | "Blue" | "Yellow";
type PrimaryColors = "Red" | "Blue";
type SecondaryColors = Exclude<AllColors, PrimaryColors>;
const secondaryColor: SecondaryColors = "Green"; // Valid
const invalidColor: SecondaryColors = "Red"; // Error: Type '"Red"' is not assignable to type 'SecondaryColors'.
In this example:
We have a union type
AllColorsthat represents all possible colors.We also have a union type
PrimaryColorsthat represents primary colors.We use the
Exclude<AllColors, PrimaryColors>utility type to create a new typeSecondaryColorsthat excludes values fromAllColorsthat are assignable toPrimaryColors. This effectively gives us the secondary colors.We assign the value
"Green"tosecondaryColor, which is valid because it's a secondary color.Attempting to assign the value
"Red"toinvalidColorresults in a TypeScript error because"Red"is a primary color and cannot be a secondary color.
The Exclude<T, U> utility type is useful for creating new types that exclude specific values from a given union type, allowing you to enforce type safety in your code.
-
Extract<T, U>: Extracts values in typeUfrom typeT.
Certainly, here's an example of how to use the Extract utility type in TypeScript:
// Define a type for different shapes
type Shape = "circle" | "square" | "triangle";
// Define a type for filled shapes
type FilledShape = "circle" | "square";
// Use the Extract utility type to extract common shapes
type CommonShape = Extract<Shape, FilledShape>;
// Create a variable of type CommonShape
const shape: CommonShape = "square"; // Valid
// Attempting to assign a non-matching shape will result in a type error
// const invalidShape: CommonShape = "triangle"; // Error: Type '"triangle"' is not assignable to type 'CommonShape'.
In this example:
We have a type
Shaperepresenting different shapes: "circle," "square," and "triangle."We have a type
FilledShaperepresenting filled shapes: "circle" and "square."We use the
Extractutility type to create a new typeCommonShapethat extracts shapes common to bothShapeandFilledShape.We create a variable
shapeof typeCommonShapeand assign it a value that matches the common shapes, which is "square."Attempting to assign a shape that is not common to both
ShapeandFilledShape, such as "triangle," will result in a TypeScript type error, ensuring type safety.
-
NonNullable<T>: Excludesnullandundefinedfrom typeT.
Certainly! Here's an example of how to use the NonNullable<T> utility type in TypeScript:
// Define a type that includes null and undefined
type NullableString = string | null | undefined;
// Use NonNullable to exclude null and undefined from the type
type NonNullString = NonNullable<NullableString>;
// Create variables with the NonNullString type
const validString: NonNullString = "Hello, TypeScript!";
const nullValue: NonNullString = null; // Error: Type 'null' is not assignable to type 'string'.
const undefinedValue: NonNullString = undefined; // Error: Type 'undefined' is not assignable to type 'string'.
In this example:
We start with a type
NullableStringthat includesstring,null, andundefined, which means it can hold either a valid string or null or undefined.We use the
NonNullable<NullableString>utility type to create a new typeNonNullString, which excludesnullandundefinedfrom the original type, ensuring that the variable can only hold valid string values.We create variables with the
NonNullStringtype and demonstrate that attempting to assignnullorundefinedto them results in TypeScript type errors, ensuring that only valid strings can be assigned to these variables.
-
ReturnType<T>: Obtains the return type of a function typeT.
Certainly! Here's an example of how to use the ReturnType<T> utility type in TypeScript:
// Define a function that returns a string
function greet(name: string): string {
return `Hello, ${name}!`;
}
// Use the ReturnType utility type to capture the return type of the function
type Greeting = ReturnType<typeof greet>;
// Create a variable of the captured return type
const message: Greeting = "Hello, Alice!";
// Attempting to assign a value of a different type will result in a type error
// const invalidMessage: Greeting = 42; // Error: Type '42' is not assignable to type 'string'.
In this example:
We define a function
greetthat takes anameparameter and returns a string greeting.We use the
ReturnType<typeof greet>utility type to capture the return type of thegreetfunction, which isstring.We create a variable
messageof typeGreeting, which is equivalent tostring.Attempting to assign a value of a different type, such as a number, to
Greetingwill result in a TypeScript type error, demonstrating the utility ofReturnTypefor ensuring the correct return type of functions.Parameters<T>: Obtains the parameter types of a function typeTas a tuple.
Certainly, here's an example of how to use the Parameters<T> utility type in TypeScript:
// Define a function type with parameters
type AddFunction = (x: number, y: number) => number;
// Use the Parameters utility type to extract parameter types
type AddFunctionArgs = Parameters<AddFunction>;
// Create a function that uses the extracted parameter types
const add: AddFunction = (a, b) => a + b;
// Valid usage with correct parameter types
const result: number = add(3, 4);
// Invalid usage with incorrect parameter types
const invalidResult: number = add("3", 4); // Error: Argument of type 'string' is not assignable to parameter of type 'number'.
In this example:
We define a function type
AddFunctionthat represents a function with two parameters of typenumberand a return type ofnumber.We use the
Parametersutility type to extract the parameter types from theAddFunctiontype. This results in theAddFunctionArgstype, which is a tuple of the parameter types.We create a function
addof typeAddFunctionthat takes two parameters,aandb, and returns their sum.We use the
addfunction with valid parameter types (number) to compute the sum, which is7.We also attempt to use the
addfunction with invalid parameter types (stringandnumber), which results in a TypeScript error due to type incompatibility.
This example demonstrates how the Parameters<T> utility type can be used to extract parameter types from a function type and ensure type safety when working with functions.
-
InstanceType<T>: Obtains the instance type of a constructor function typeT.
Certainly, here's an example of how to use the InstanceType<T> utility type in TypeScript:
// Define a class with a constructor
class Product {
constructor(public name: string, public price: number) {}
}
// Use the InstanceType utility type to obtain the instance type of the Product class
type ProductInstance = InstanceType<typeof Product>;
// Create an instance of the Product class
const product: ProductInstance = new Product("Laptop", 999);
// Access properties and methods of the instance
console.log(`Product: ${product.name}, Price: $${product.price}`);
In this example:
We define a
Productclass with a constructor that takes anameand aprice.We use the
InstanceType<typeof Product>utility type to obtain the instance type of theProductclass. This allows us to create instances with the same shape asProduct.We create an instance
productof typeProductInstance, passing the required constructor parameters.We can access the properties and methods of the
productinstance, ensuring type safety and code clarity.
==========================================================================================================================
*# 3. Object-Oriented Programming (OOP) with TypeScript
*
3-0: Introduction of Object Oriented Programming
3-1: Class and object
{
// oop - class
class Animal {
constructor(
public name: string,
public species: string,
public sound: string
) {}
makeSound() {
console.log(`The ${this.name} says ${this.sound}`);
}
}
const dog = new Animal("German Shepard Bhai", "dog", "Ghew Ghew");
const cat = new Animal("Persian bhai", "cat", "meaw meaw");
cat.makeSound();
//
}
3-2: Inheritance in OOP.
{
// oop - inheritence
class Person {
name: string;
age: number;
address: string;
constructor(name: string, age: number, address: string) {
this.name = name;
this.age = age;
this.address = address;
}
getSleep(numOfHours: number) {
console.log(`${this.name} will sleep for ${numOfHours}`);
}
}
class Student extends Person {
constructor(name: string, age: number, address: string) {
super(name, age, address)
}
}
const student1 = new Student("Mr. student", 20, "Uganda");
student1.
class Teacher extends Person{
designation: string
constructor(name: string, age: number, address: string,designation: string) {
super(name, age , address)
this.designation = designation
}
takeClass(numOfClass: number){
console.log(`${this.name} will take ${numOfClass}`);
}
}
const teacher = new Teacher("Mr. teacher", 40, "Uganda","professor");
teacher.
//
}
3-3: Type guard using typeof & in
"role" in user
typeof param1 === "number"
{
// type guards
// typeof --> type guard
type Alphaneumeric = string | number;
const add = (param1: Alphaneumeric, param2: Alphaneumeric): Alphaneumeric => {
if (typeof param1 === "number" && typeof param2 === "number") {
return param1 + param2;
} else {
return param1.toString() + param2.toString();
}
};
const result1 = add("2", "3");
console.log(result1);
// in guard
type NormalUser = {
name: string;
};
type AdminUser = {
name: string;
role: "admin";
};
const getUser = (user: NormalUser | AdminUser) => {
if ("role" in user) {
console.log(`My name is ${user.name} and my role is ${user.role}`);
} else {
console.log(`My name is ${user.name}`);
}
};
const normalUser: NormalUser = {
name: "Mr. Normal Bhai",
};
const adminUser: AdminUser = {
name: "Mr. Admin Bhai",
role: "admin",
};
getUser(adminUser);
//
}
3-4: Type guard using instance of
animal instanceof Dog;
animal instanceof Cat;
const isDog = (animal: Animal): animal is Dog => {
return animal instanceof Dog;
};
{
// instanceof guard
class Animal {
name: string;
species: string;
constructor(name: string, species: string) {
this.name = name;
this.species = species;
}
makeSound() {
console.log("I am making sound");
}
}
class Dog extends Animal {
constructor(name: string, species: string) {
super(name, species);
}
makeBark() {
console.log("I am barking");
}
}
class Cat extends Animal {
constructor(name: string, species: string) {
super(name, species);
}
makeMeaw() {
console.log("I am mewaing");
}
}
// smart way tge handle korar jnne chaile amra function bebohar krte pari
const isDog = (animal: Animal): animal is Dog => {
return animal instanceof Dog;
};
const isCat = (animal: Animal): animal is Cat => {
return animal instanceof Cat;
};
const getAnimal = (animal: Animal) => {
if (isDog(animal)) {
animal.makeBark();
} else if (isCat(animal)) {
animal.makeMeaw();
} else {
animal.makeSound();
}
};
const dog = new Dog("Dog Bhai", "dog");
const cat = new Cat("Cat Bhai", "cat");
getAnimal(cat);
//
}
3-5: Access modifiers
public readonly id: number;
public name: string;
private _balance: number;
this._balance = balance;
{
// access modifiers
class BankAccount {
public readonly id: number;
public name: string;
private _balance: number;
constructor(id: number, name: string, balance: number) {
this.id = id;
this.name = name;
this._balance = balance;
}
public addDeposit(amount: number) {
this._balance = this._balance + amount;
}
public getBalance() {
return this._balance;
}
}
class StudentAccount extends BankAccount{
test(){
this.
}
}
const goribManusherAccount = new BankAccount(111, "Mr. gorib", 20);
// goribManusherAccount.balance = 0;
goribManusherAccount.addDeposit(20);
const myBalance = goribManusherAccount.getBalance();
console.log(myBalance);
//
}
3-6: Getter and setter
set deposit(amount: number) {
this._balance = this.balance + amount;
}
get balance() {
return this._balance;
}
{
// getter and setter
class BankAccount {
public readonly id: number;
public name: string;
protected _balance: number;
constructor(id: number, name: string, balance: number) {
this.id = id;
this.name = name;
this._balance = balance;
}
set deposit(amount: number) {
this._balance = this.balance + amount;
}
// public addDeposit(amount: number) {
// this._balance = this._balance + amount;
// }
//getter
get balance() {
return this._balance;
}
// public getBalance() {
// return this._balance;
// }
}
const goribManusherAccount = new BankAccount(111, "Mr. gorib", 50);
// goribManusherAccount.deposit = 0;
// goribManusherAccount.addDeposit(20); // function call korte hsse
goribManusherAccount.deposit = 50;
// const myBalance = goribManusherAccount.getBalance(); // function call korte hsse
const myBalance = goribManusherAccount.balance; // property er mto kore
console.log(myBalance);
//
}
3-7 Statics in OOP
=> if use static in anyy variable then have to use classname dot variable name to access.
static count: number = 0;
return (Counter.count = Counter.count + 1);
=>if use static in the function then during the log we have to use classname dot function.
static increment() {
}
console.log(Counter.increment());
{
// static
class Counter {
static count: number = 0;
static increment() {
return (Counter.count = Counter.count + 1);
}
static decrement() {
return (Counter.count = Counter.count - 1);
}
}
// const instance1 = new Counter();
console.log(Counter.increment()); // 1 -> different memory
// 1 -> different memory
// const instance2 = new Counter();
console.log(Counter.increment()); // 1 --> different memory
// 1 --> different memory
// const instance3 = new Counter();
console.log(Counter.increment());
//
}
3-8 Polymorphism
{
// polymorphisom
class Person {
getSleep() {
console.log(`I am sleeping for 8 hours per day`);
}
}
class Student extends Person {
getSleep() {
console.log(`I am sleeping for 7 hours per day`);
}
}
class Developer extends Person {
getSleep() {
console.log(`I am sleeping for 6 hours per day`);
}
}
const getSleepingHours = (param: Person) => {
param.getSleep();
};
const person1 = new Person();
const person2 = new Student();
const person3 = new Developer();
getSleepingHours(person1);
getSleepingHours(person2);
getSleepingHours(person3);
class Shape {
getArea(): number {
return 0;
}
}
// pi* r* r
class Circle extends Shape {
radius: number;
constructor(radius: number) {
super();
this.radius = radius;
}
getArea(): number {
return Math.PI * this.radius * this.radius;
}
}
// height * width
class Reactangle extends Shape {
height: number;
width: number;
constructor(height: number, width: number) {
super();
this.height = height;
this.width = width;
}
getArea(): number {
return this.height * this.width;
}
}
const getShapeArea = (param: Shape) => {
console.log(param.getArea());
};
const shape1 = new Shape();
const shape2 = new Circle(10);
const shape3 = new Reactangle(10, 20);
getShapeArea(shape3);
//
}
3-9 Abstraction in OOP
`interface Vehicle1 `
`class Car1 implements Vehicle1`
`abstract class Car2`
`class ToyotaCar extends Car2 `
abstract class Car2 {I am just testing
abstract startEngine(): void;
abstract stopEngine(): void;
abstract move(): void;
test() {
console.log();
}
}
{
// abstraction : 1. interface 2. abstract
// idea
interface Vehicle1 {
startEngine(): void;
stopEngine(): void;
move(): void;
}
// real implementation
class Car1 implements Vehicle1 {
startEngine(): void {
console.log(`I am starting the car engine`);
}
stopEngine(): void {
console.log("I am stopping the car engine");
}
move(): void {
console.log(`I am moving the car`);
}
test() {
console.log(`I am just testing`);
}
}
const toyotaCar = new Car1();
toyotaCar.startEngine();
// abstract class
// idea
abstract class Car2 {
abstract startEngine(): void;
abstract stopEngine(): void;
abstract move(): void;
test() {
console.log(`I am just testing`);
}
}
class ToyotaCar extends Car2 {
startEngine(): void {
console.log("I am starting the car engine");
}
stopEngine(): void {
console.log("I am stopping the car engine");
}
move(): void {
console.log("I am moving the car");
}
}
// const hondaCar = new Car2();
// hondaCar.startEngine();
//
}
3-10: Encapsulation in OOP
public readonly id: number;
public name: string;
protected _balance: number;
private getBalance() {
return this._balance;
}
getHiddenMethod(){
return this.getBalance()
}
---
class StudentAccount extends BankAccount{
test(){
this.
}
{
// access modifiers
class BankAccount {
public readonly id: number;
public name: string;
protected _balance: number;
constructor(id: number, name: string, balance: number) {
this.id = id;
this.name = name;
this._balance = balance;
}
public addDeposit(amount: number) {
this._balance = this._balance + amount;
}
private getBalance() {
return this._balance;
}
getHiddenMethod(){
return this.getBalance()
}
}
class StudentAccount extends BankAccount{
test(){
this.
}
}
const goribManusherAccount = new BankAccount(111, "Mr. gorib", 20);
// goribManusherAccount.balance = 0;
goribManusherAccount.addDeposit(20);
const myBalance = goribManusherAccount.getBalance();
console.log(myBalance);
goribManusherAccount.
//
}




















































Top comments (0)