DEV Community

Cover image for Mission 1: Be a typescript technocrat
Kazi Abdur Rakib
Kazi Abdur Rakib

Posted on • Edited on

Mission 1: Be a typescript technocrat

_
**

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
Enter fullscreen mode Exit fullscreen mode

This command will download and execute the nvm installation script.

After the installation is complete, close and reopen your terminal, or run:

source ~/.bashrc
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:

  1. List the available Node.js versions to see which versions are installed and available for use:
nvm ls
Enter fullscreen mode Exit fullscreen mode

This will list the installed Node.js versions, and the currently active version will be indicated with an arrow.

  1. 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
Enter fullscreen mode Exit fullscreen mode

This command will set the active Node.js version to 20.9.0.

  1. You can verify that you've switched to Node.js version 20.9.0 by running:
node -v
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Image description

Typescript config file
: tsc --init
then we ill get a tsconfig.json file, then we will edit it:

  1. search rootDir; then write typescritp file location in this rootDir

Image description

  1. search outDir, write path of my typescript file will store in which location.

Image description

Image description

after that write tsc.
Image description

some extra package. to run typescript code directly

1. Install ts-node-dev globally (recommended):

npm install -g ts-node-dev
Enter fullscreen mode Exit fullscreen mode

2. Use npx (without installing globally):

ts-node-dev --respawn --transpile-only filelocation/filename.ts
Enter fullscreen mode Exit fullscreen mode
npx ts-node-dev --respawn --transpile-only ./module1/src/index.ts

Enter fullscreen mode Exit fullscreen mode

1-4 Basic data types

Certainly! Here are examples of various data types in TypeScript:

  1. Integer (int):
   const age: number = 30;
Enter fullscreen mode Exit fullscreen mode
  1. Floating-Point (float and double):
   const pi: number = 3.14159;
Enter fullscreen mode Exit fullscreen mode
  1. Boolean (bool):
   const isTrue: boolean = true;
Enter fullscreen mode Exit fullscreen mode
  1. Character (char):

In TypeScript, characters are represented as single-character strings:

   const firstLetter: string = "A";
Enter fullscreen mode Exit fullscreen mode
  1. String:
   const greeting: string = "Hello, TypeScript!";
Enter fullscreen mode Exit fullscreen mode
  1. Null:
   const nullValue: null = null;
Enter fullscreen mode Exit fullscreen mode
  1. Undefined (or None):
   let undefinedValue: undefined;
Enter fullscreen mode Exit fullscreen mode
  1. Void:

Functions with no return value have a void type:

   function sayHello(): void {
     console.log("Hello, world!");
   }
Enter fullscreen mode Exit fullscreen mode
  1. Symbol:
   const uniqueSymbol: symbol = Symbol("description");
Enter fullscreen mode Exit fullscreen mode
  1. Byte:

    TypeScript doesn't have a specific byte data type, but you can work with bytes using number or Uint8Array.

  2. Date and Time:

    TypeScript can work with date and time using JavaScript's Date object:

    const currentDate: Date = new Date();
    
  3. BigInteger and BigDecimal:

    TypeScript supports large integers through the BigInt type:

    const bigIntValue: bigint = 1234567890123456789012345678901234567890n;
    
  4. Array:

    Arrays in TypeScript can hold multiple values of the same data type:

    const numbers: number[] = [1, 2, 3, 4, 5];
    
  5. Tuple:

    Tuples allow you to specify the types and order of elements in a fixed-size collection:

    const person: [string, number] = ["Alice", 30];
    
  6. Enum:

    Enums define a set of named constant values:

    enum Color {
      Red,
      Green,
      Blue,
    }
    
    const selectedColor: Color = Color.Red;
    
  7. Any:

    The any type 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!";
    
  8. Union Types:

    Union types allow variables to hold values of multiple types:

    let mixedValue: number | string = 42;
    mixedValue = "Hello, World!";
    
  9. 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 };
    
  10. Object:

    The object type represents non-primitive values, such as functions, arrays, and objects:

    const user: object = { name: "Alice", age: 30 };
    
  11. 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.

Image description
Image description
Image description
Image description

Image description

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.

  1. Number: Used for numeric values (integers and floating-point numbers).
   let age: number = 30;
   let pi: number = 3.14;
Enter fullscreen mode Exit fullscreen mode
  1. String: Used for text and character data.
   let name: string = "John";
   let message: string = 'Hello, TypeScript!';
Enter fullscreen mode Exit fullscreen mode
  1. Boolean: Represents true or false values.
   let isStudent: boolean = true;
   let isWorking: boolean = false;
Enter fullscreen mode Exit fullscreen mode
  1. 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"];
Enter fullscreen mode Exit fullscreen mode

1-5 Object , Optional and Literal

Here are examples of TypeScript data types and features related to objects, optional properties, and literals:

  1. 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,
   };
Enter fullscreen mode Exit fullscreen mode
  1. 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
   };
Enter fullscreen mode Exit fullscreen mode
  1. Literal Types:

TypeScript allows you to define literal types where a variable can only have a specific, literal value.

   const status: "active" | "inactive" = "active";
Enter fullscreen mode Exit fullscreen mode
  1. 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",
   };
Enter fullscreen mode Exit fullscreen mode
  1. 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
   };
Enter fullscreen mode Exit fullscreen mode
  1. 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,
   };
Enter fullscreen mode Exit fullscreen mode
  1. 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",
   };
Enter fullscreen mode Exit fullscreen mode

Image description
=>Readonly property

Image description

Image description

1-6 Function in typescript

Image description

Image description

Image description

Image description

1-7 Spread and Rest Operator

Certainly! Here are examples of the spread and rest operators in TypeScript:

  1. 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 };
    
  1. 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.
}

Image description

Image description

Image description

Image description

Image description

Image description

Image description

Image description

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:

  1. 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]
Enter fullscreen mode Exit fullscreen mode
  1. 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
Enter fullscreen mode Exit fullscreen mode
  1. 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
Enter fullscreen mode Exit fullscreen mode
  1. 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
Enter fullscreen mode Exit fullscreen mode
  1. 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"
Enter fullscreen mode Exit fullscreen mode

Image description

Image description

Image description

Image description

...rest

Image description

1-9 Type alias in typescript

Image description

Image description

Image description

Image description

Image description

1-10 Union and Intersection types

Image description

Image description

Image description

Image description

Image description

Image description

1-11 Ternary, optional chaining & nullish coalescing operator

1. nullish operator(??) its works for Null and undefined. not for "" .
Image description

Image description

Image description

Image description

1-12 Never,unknown and nullable type

Certainly! Here are examples of TypeScript data types and features related to never, unknown, and nullable types:

  1. never Type:

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
     }
   }
Enter fullscreen mode Exit fullscreen mode
  1. unknown Type:

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;
   }
Enter fullscreen mode Exit fullscreen mode
  1. 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";
Enter fullscreen mode Exit fullscreen mode
  1. Using null and undefined Together:

You can create a type that allows both null and undefined values.

   let value: number | null | undefined = null;
Enter fullscreen mode Exit fullscreen mode
  1. 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;
Enter fullscreen mode Exit fullscreen mode
  1. 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);
Enter fullscreen mode Exit fullscreen mode
  1. 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
Enter fullscreen mode Exit fullscreen mode

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.

  1. Nullable type Image description
  2. unknown type Image description 3.Never

Image description

========================================================================

*## 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);
  }

  //
}
Enter fullscreen mode Exit fullscreen mode

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",
  };
Enter fullscreen mode Exit fullscreen mode
  interface User2 {
    name: string;
    age: number;
  }

  interface UserWithRole2 extends User2 {
    role: string;
  }

  const user1: UserWithRole2 = {
    name: "Persian",
    age: 100,
    role: "manager",
  };
Enter fullscreen mode Exit fullscreen mode
  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
Enter fullscreen mode Exit fullscreen mode
  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

Enter fullscreen mode Exit fullscreen mode

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" },
  ];
}
Enter fullscreen mode Exit fullscreen mode
// 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" }]


Enter fullscreen mode Exit fullscreen mode

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",
    },
  };

  //
}

Enter fullscreen mode Exit fullscreen mode

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",
  });

  //
}

Enter fullscreen mode Exit fullscreen mode

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",
  });

  //
}
Enter fullscreen mode Exit fullscreen mode

2-7: Constraint using key of

The keyof operator is useful in TypeScript for several reasons:

  1. 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.

  2. 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.

  3. 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.

  4. 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"'.
Enter fullscreen mode Exit fullscreen mode

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();

  //
}
Enter fullscreen mode Exit fullscreen mode

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">;
  //
}
Enter fullscreen mode Exit fullscreen mode

2-10: Mapped types

  type AreaString<T> = {
    [key in keyof T]: T[key];
  };
Enter fullscreen mode Exit fullscreen mode
{
  // 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,
  };

  //
}
Enter fullscreen mode Exit fullscreen mode
  // 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,
  };
Enter fullscreen mode Exit fullscreen mode

2-11 Utility types

Certainly, let's go through some examples of TypeScript utility types:

  1. Partial<T>: Makes all properties of a type T optional.

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);
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We start with a User type representing a user object with properties like id, username, email, and age.

  • We create a complete user object completeUser with all properties defined.

  • We use the Partial<User> utility type to create a new type PartialUser where all properties of the User type are optional.

  • We create a partial user object partialUser of type PartialUser with 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 User type, such as the country property.

  • We create another partial user partialUserWithAge with the age property defined.

  • Finally, we merge a complete user (completeUser) with a partial user with an age property (partialUserWithAge) to create a new user object (mergedUser). This showcases how you can combine complete and partial objects to get a merged result.

  1. Required<T>: Makes all properties of a type T required. Certainly, here's an example of the Required<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,
// };
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We have a type User with optional properties, indicated by the ? after each property name.

  • We use the Required<T> utility type to create a new type RequiredUser where all properties are required.

  • We create an object user of type RequiredUser with all properties present, which is valid.

  • Attempting to create an object incompleteUser of type RequiredUser with missing properties results in a TypeScript type error, enforcing that all properties are required for objects of this type.

  1. Readonly<T>: Makes all properties of a type T read-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.
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We have a type Person representing a person with properties name and age.

  • We use the Readonly<T> utility type to create a new type ReadonlyPerson, which makes all properties of Person read-only.

  • We create an object person of type ReadonlyPerson. Attempting to modify any of its properties, such as name and age, results in TypeScript type errors. This ensures that the object remains immutable and read-only once it's defined.

  1. Record<K, T>: Creates an object type with keys of type K and values of type T.

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'.
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We define a type CartItem to represent an item in a shopping cart, which includes a productId and a quantity.

  • We use the Record<K, T> utility type to create a type ShoppingCart, which represents a shopping cart with keys of type string (product IDs) and values of type CartItem.

  • We create a shoppingCart object with some items, where each item is associated with a product ID (string key) and a CartItem value.

  • 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.

  1. Pick<T, K>: Selects specific properties from a type T.

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'.
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We have a type User representing a user object with properties like id, username, email, and age.

  • We use the Pick utility type to create a new type UserIdentity by selecting specific properties "id" and "username" from the User type.

  • We then create an object user of type UserIdentity, 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.

  1. Omit<T, K>: Excludes specific properties from a type T.

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'.
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We have a type User representing a user object with properties like id, username, email, and age.

  • We use the Omit utility type to create a new type UserWithoutEmail by excluding the property "email" from the User type.

  • We then create an object user of type UserWithoutEmail, 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.

  1. Exclude<T, U>: Excludes values in type U from type T.

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'.
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We have a union type AllColors that represents all possible colors.

  • We also have a union type PrimaryColors that represents primary colors.

  • We use the Exclude<AllColors, PrimaryColors> utility type to create a new type SecondaryColors that excludes values from AllColors that are assignable to PrimaryColors. This effectively gives us the secondary colors.

  • We assign the value "Green" to secondaryColor, which is valid because it's a secondary color.

  • Attempting to assign the value "Red" to invalidColor results 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.

  1. Extract<T, U>: Extracts values in type U from type T.

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'.
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We have a type Shape representing different shapes: "circle," "square," and "triangle."

  • We have a type FilledShape representing filled shapes: "circle" and "square."

  • We use the Extract utility type to create a new type CommonShape that extracts shapes common to both Shape and FilledShape.

  • We create a variable shape of type CommonShape and assign it a value that matches the common shapes, which is "square."

  • Attempting to assign a shape that is not common to both Shape and FilledShape, such as "triangle," will result in a TypeScript type error, ensuring type safety.

  1. NonNullable<T>: Excludes null and undefined from type T.

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'.
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We start with a type NullableString that includes string, null, and undefined, which means it can hold either a valid string or null or undefined.

  • We use the NonNullable<NullableString> utility type to create a new type NonNullString, which excludes null and undefined from the original type, ensuring that the variable can only hold valid string values.

  • We create variables with the NonNullString type and demonstrate that attempting to assign null or undefined to them results in TypeScript type errors, ensuring that only valid strings can be assigned to these variables.

  1. ReturnType<T>: Obtains the return type of a function type T.

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'.
Enter fullscreen mode Exit fullscreen mode

In this example:

  1. We define a function greet that takes a name parameter and returns a string greeting.

  2. We use the ReturnType<typeof greet> utility type to capture the return type of the greet function, which is string.

  3. We create a variable message of type Greeting, which is equivalent to string.

  4. Attempting to assign a value of a different type, such as a number, to Greeting will result in a TypeScript type error, demonstrating the utility of ReturnType for ensuring the correct return type of functions.

  5. Parameters<T>: Obtains the parameter types of a function type T as 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'.
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We define a function type AddFunction that represents a function with two parameters of type number and a return type of number.

  • We use the Parameters utility type to extract the parameter types from the AddFunction type. This results in the AddFunctionArgs type, which is a tuple of the parameter types.

  • We create a function add of type AddFunction that takes two parameters, a and b, and returns their sum.

  • We use the add function with valid parameter types (number) to compute the sum, which is 7.

  • We also attempt to use the add function with invalid parameter types (string and number), 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.

  1. InstanceType<T>: Obtains the instance type of a constructor function type T.

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}`);
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We define a Product class with a constructor that takes a name and a price.

  • We use the InstanceType<typeof Product> utility type to obtain the instance type of the Product class. This allows us to create instances with the same shape as Product.

  • We create an instance product of type ProductInstance, passing the required constructor parameters.

  • We can access the properties and methods of the product instance, ensuring type safety and code clarity.

==========================================================================================================================

*# 3. Object-Oriented Programming (OOP) with TypeScript
*

3-0: Introduction of Object Oriented Programming

Image description

Image description

Image description

Image description

Image description

Image description

Image description

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();

  //
}
Enter fullscreen mode Exit fullscreen mode

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.
  //
} 
Enter fullscreen mode Exit fullscreen mode

3-3: Type guard using typeof & in

"role" in user
typeof param1 === "number"
Enter fullscreen mode Exit fullscreen mode
{
  // 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);

  //
}
Enter fullscreen mode Exit fullscreen mode

3-4: Type guard using instance of

animal instanceof Dog;
animal instanceof Cat;
Enter fullscreen mode Exit fullscreen mode
  const isDog = (animal: Animal): animal is Dog => {
    return animal instanceof Dog;
  };
Enter fullscreen mode Exit fullscreen mode
{
  // 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);

  //
}
Enter fullscreen mode Exit fullscreen mode

3-5: Access modifiers

    public readonly id: number;
    public name: string;
    private _balance: number;
Enter fullscreen mode Exit fullscreen mode
this._balance = balance;
Enter fullscreen mode Exit fullscreen mode
{
  // 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);

  //
}
Enter fullscreen mode Exit fullscreen mode

3-6: Getter and setter

    set deposit(amount: number) {
      this._balance = this.balance + amount;
    }
Enter fullscreen mode Exit fullscreen mode
    get balance() {
      return this._balance;
    }
Enter fullscreen mode Exit fullscreen mode
{
  // 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);

  //
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode
=>if use static in the function then during the log we have to use classname dot function.
 static increment() {
}
console.log(Counter.increment());
Enter fullscreen mode Exit fullscreen mode
{
  // 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());
  //
}
Enter fullscreen mode Exit fullscreen mode

3-8 Polymorphism

Image description

{
  // 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);

  //
}
Enter fullscreen mode Exit fullscreen mode

3-9 Abstraction in OOP

`interface Vehicle1 `
`class Car1 implements Vehicle1`
`abstract class Car2`
`class ToyotaCar extends Car2 `
Enter fullscreen mode Exit fullscreen mode

abstract class Car2 {
abstract startEngine(): void;
abstract stopEngine(): void;
abstract move(): void;
test() {
console.log(
I am just testing);
}
}

{
  // 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();

  //
}
Enter fullscreen mode Exit fullscreen mode

3-10: Encapsulation in OOP

    public readonly id: number;
    public name: string;
    protected _balance: number;
   private getBalance() {
      return this._balance;
    }
Enter fullscreen mode Exit fullscreen mode
    getHiddenMethod(){
      return this.getBalance()
    }

---
  class StudentAccount extends BankAccount{
    test(){
      this.
    }

Enter fullscreen mode Exit fullscreen mode
{
  // 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.

  //
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)