Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
muratdemirci committed Feb 7, 2024
0 parents commit 1f0ca2f
Show file tree
Hide file tree
Showing 54 changed files with 4,447 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
Binary file added Classes & Interfaces/.DS_Store
Binary file not shown.
45 changes: 45 additions & 0 deletions Classes & Interfaces/Constructor Functions & The this Keyword.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Constructor Functions & The "this" Keyword

## Introduction

Constructor functions in TypeScript are used to create and initialize objects based on a class. These functions are called when an instance of the class is created using the `new` keyword. The `this` keyword refers to the instance being created, allowing you to set and access properties specific to that instance.

## Example
```tsx
class Person {
// Properties
name: string;
age: number;

// Constructor function
constructor(name: string, age: number) {
// Using the "this" keyword to refer to instance properties
this.name = name;
this.age = age;
}

// Method
introduce(): string {
return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
}
}

// Creating an instance of the class using the constructor
const person1 = new Person("Alice", 25);

// Accessing properties and calling methods
console.log(person1.name); // Output: Alice
console.log(person1.age); // Output: 25
console.log(person1.introduce()); // Output: Hello, my name is Alice and I am 25 years old.
```

In this example:

1. The `Person` class has two properties, `name` and `age`, and a constructor function that initializes these properties when an instance is created.
2. Inside the constructor, `this` refers to the instance being created (e.g., `person1`). The properties `name` and `age` are assigned values specific to that instance.
3. The `introduce` method uses `this` to access the properties of the instance it is called on.
4. When `person1.introduce()` is called, the `this` keyword inside the `introduce` method refers to `person1`, and the method returns a string using the properties of that instance.

It's important to note that the use of classes and constructor functions is a feature of ES6 (ECMAScript 2015) and later versions of JavaScript. TypeScript enhances this by providing static typing and additional features.

In summary, constructor functions in TypeScript play a crucial role in initializing object instances by setting their properties using the `this` keyword. They contribute to creating organized and reusable code with class-based structures.
77 changes: 77 additions & 0 deletions Classes & Interfaces/Getters & Setters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Getters & Setters

## Introduction

Getters and setters are special methods that allow you to control the access and modification of class properties. Getters are used to retrieve the value of a property, while setters are used to modify the value of a property. They provide a way to encapsulate the internal representation of an object and add behavior when getting or setting its properties.

Here's an example demonstrating the use of getters and setters:

```tsx
class Circle {
private _radius: number;

constructor(radius: number) {
this._radius = radius;
}

// Getter for the radius property
get radius(): number {
console.log("Getting radius");
return this._radius;
}

// Setter for the radius property
set radius(newRadius: number) {
if (newRadius >= 0) {
console.log("Setting radius");
this._radius = newRadius;
} else {
console.error("Radius must be a non-negative value");
}
}

// Getter for calculating the area
get area(): number {
console.log("Calculating area");
return Math.PI * this._radius ** 2;
}
}

// Creating an instance of the class
const myCircle = new Circle(5);

// Using the getter to retrieve the radius
console.log(myCircle.radius); // Output: Getting radius, 5

// Using the setter to update the radius
myCircle.radius = 8; // Output: Setting radius

// Using the getter for calculating the area
console.log(myCircle.area); // Output: Calculating area, 201.06192982974676

// Attempting to set a negative radius (error message from the setter)
myCircle.radius = -3; // Output: Radius must be a non-negative value
```

In this example:

- The `Circle` class has a private property `_radius` and exposes it using a getter and setter.
- The getter for `radius` allows retrieving the value of the `_radius` property with additional behavior (in this case, logging).
- The setter for `radius` allows updating the value of `_radius` with validation logic to ensure the radius is non-negative.
- A getter for `area` is included, demonstrating that getters can be used for computed properties.
- The instance of `Circle` (`myCircle`) is created and accessed using the getter and setter.

### Use Cases:

1. **Encapsulation:**
- Getters and setters provide a way to encapsulate the internal representation of an object, allowing controlled access to properties.
2. **Validation:**
- Setters can include validation logic to ensure that property values meet certain criteria.
3. **Computed Properties:**
- Getters can be used to calculate and return derived or computed properties based on other properties.
4. **Logging and Side Effects:**
- Getters and setters can be used to log property access or modification and perform additional side effects.
5. **Property Access Control:**
- Getters and setters allow you to control read and write access to properties, enabling fine-grained access control.

By using getters and setters in TypeScript, you can design classes that provide a clean and controlled interface for accessing and modifying their properties, promoting encapsulation and maintaining the integrity of the object's state.
113 changes: 113 additions & 0 deletions Classes & Interfaces/Inheritance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Inheritance

## Introduction

Inheritance is a mechanism that allows a class (called the derived or child class) to inherit properties and methods from another class (called the base or parent class). This promotes code reuse and the creation of hierarchies of related classes. The `extends` keyword is used to establish inheritance.

```tsx
// Base class
class Animal {
// Properties
name: string;

// Constructor
constructor(name: string) {
this.name = name;
}

// Method
makeSound(): string {
return "Some generic sound";
}
}

// Derived class inheriting from Animal
class Dog extends Animal {
// Additional property
breed: string;

// Constructor
constructor(name: string, breed: string) {
// Calling the constructor of the base class using super()
super(name);
this.breed = breed;
}

// Overriding the makeSound method
makeSound(): string {
return "Woof!";
}

// Additional method
fetch(): string {
return "Fetching the ball!";
}
}

// Creating an instance of the derived class
const myDog = new Dog("Buddy", "Golden Retriever");

// Accessing inherited properties and methods
console.log(myDog.name); // Output: Buddy
console.log(myDog.makeSound()); // Output: Woof!
console.log(myDog.fetch()); // Output: Fetching the ball!
```

In this example:

- The `Animal` class is the base class, and the `Dog` class is the derived class.
- The `Dog` class uses the `extends` keyword to inherit from the `Animal` class.
- The `super` keyword is used in the constructor of the derived class to call the constructor of the base class and initialize inherited properties.
- The `makeSound` method is overridden in the derived class, providing a specific implementation for dogs.
- The `Dog` class introduces an additional property (`breed`) and an additional method (`fetch`).

### Access Modifiers in Inheritance:

In TypeScript, access modifiers (`public`, `protected`, and `private`) can be used to control the visibility of members within a class and its subclasses:

- `public`: Visible to everyone (default if not specified).
- `protected`: Visible to the class and its subclasses.
- `private`: Visible only within the class.

```tsx
class Animal {
private age: number;

constructor(age: number) {
this.age = age;
}

protected getAge(): number {
return this.age;
}
}

class Dog extends Animal {
// The age property is not directly accessible here

getDogAge(): number {
// Accessing the protected method from the base class
return this.getAge();
}
}

const myDog = new Dog(3);
// Error: Property 'age' is private and only accessible within class 'Animal'.
// console.log(myDog.age);

// Accessing the protected method from the derived class
console.log(myDog.getDogAge()); // Output: 3
```

### Use Cases:

- **Code Reusability:**
- Inheritance allows the reuse of code from existing classes, reducing redundancy.
- **Polymorphism:**
- Derived classes can provide specific implementations for methods defined in the base class, allowing polymorphic behavior.
- **Extending Functionality:**
- Derived classes can extend the functionality of the base class by introducing new properties and methods.
- **Creating Hierarchies:**
- Inheritance is useful for creating class hierarchies, representing relationships between different types of objects.

Inheritance is a powerful feature in TypeScript that enables the creation of more organized and reusable code by allowing classes to build upon the functionality of other classes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Overriding Properties & The "protected" Modifier

## Introduction

When you extend a class and override its methods or properties, you can use the `protected` modifier to control access to those members. The `protected` modifier allows the member to be accessed within the class and its subclasses but not from external code.

Here's an example demonstrating property overriding and the use of the `protected` modifier:

```tsx
// Base class
class Animal {
// Protected property
protected sound: string;

// Constructor
constructor(sound: string) {
this.sound = sound;
}

// Method
makeSound(): string {
return this.sound;
}
}

// Derived class inheriting from Animal
class Dog extends Animal {
// Constructor with additional parameter
constructor(sound: string, private breed: string) {
// Calling the constructor of the base class using super()
super(sound);
}

// Overriding the makeSound method
makeSound(): string {
// Accessing the protected property from the base class
const baseSound = super.makeSound();

// Adding breed information
return `${baseSound} (Breed: ${this.breed})`;
}
}

// Creating an instance of the derived class
const myDog = new Dog("Woof", "Golden Retriever");

// Accessing overridden method
console.log(myDog.makeSound()); // Output: Woof (Breed: Golden Retriever)

// Accessing the protected property from the base class is not allowed externally
// Error: Property 'sound' is protected and only accessible within class 'Animal' and its subclasses.
// console.log(myDog.sound);
```

In this example:

- The `Animal` class has a `protected` property `sound`. This property is accessible within the class and its subclasses but not externally.
- The `Dog` class extends `Animal` and overrides the `makeSound` method. It uses the `super` keyword to call the overridden method from the base class.
- The `Dog` class has an additional private property (`breed`), and the `makeSound` method combines the base sound with the breed information.
- The `sound` property from the base class is not directly accessible from external code.

### Use Cases:

1. **Overriding Methods:**
- The `protected` modifier is often used when overriding methods to allow subclasses to access and modify certain aspects of the behavior.
2. **Extending Functionality:**
- Subclasses can add additional properties or methods while building upon the functionality of the base class.
3. **Encapsulation:**
- Using `protected` helps encapsulate the internal details of a class and provides controlled access to its members.
4. **Polymorphism:**
- Overriding methods and properties enables polymorphic behavior, allowing different classes to be used interchangeably.

In summary, the `protected` modifier in TypeScript is useful when designing class hierarchies and allows for controlled access to properties and methods within a class and its subclasses. This promotes encapsulation and supports the principles of object-oriented programming.
79 changes: 79 additions & 0 deletions Classes & Interfaces/Private and Public Access Modifiers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# "Private" and "Public" Access Modifiers

## Introduction

Access modifiers in TypeScript, such as `private` and `public`, are used to control the visibility of class members (properties and methods) within a class and its subclasses. They help enforce encapsulation and define how properties and methods can be accessed from outside the class.

### `Private` Access Modifier:

When a class member is marked as `private`, it can only be accessed within the class where it is defined. It is not accessible from outside the class, including from instances of the class or its subclasses.

```tsx
class Car {
private speed: number;

constructor(speed: number) {
this.speed = speed;
}

accelerate(increment: number): void {
this.speed += increment;
}

displaySpeed(): void {
console.log(`Current speed: ${this.speed} km/h`);
}
}

// Creating an instance of the class
const myCar = new Car(50);

// Accessing a private member will result in a TypeScript compilation error
// Uncommenting the line below will result in an error:
// myCar.speed = 60;

// Calling public methods is allowed
myCar.accelerate(10);
myCar.displaySpeed(); // Output: Current speed: 60 km/h
```

In this example, the `speed` property is marked as `private`, making it inaccessible from outside the `Car` class.

### `public` Access Modifier:

By default, class members are considered `public` if no access modifier is specified. `public` members are accessible from outside the class.

```tsx
class Animal {
// By default, "legs" is public
legs: number;

constructor(legs: number) {
this.legs = legs;
}

displayLegs(): void {
console.log(`Number of legs: ${this.legs}`);
}
}

// Creating an instance of the class
const dog = new Animal(4);

// Accessing public members is allowed
dog.legs = 3; // Allowed
dog.displayLegs(); // Output: Number of legs: 3
```

In this example, the `legs` property is implicitly `public`, and it can be accessed and modified from outside the `Animal` class.

### Use Cases:

- **`private` Access Modifier:**
- Use `private` for class members that should not be accessible from outside the class. This helps encapsulate internal details and prevents external interference.
- **`public` Access Modifier:**
- By default, members are `public`, and this is suitable for properties and methods that need to be accessed externally.
- **Encapsulation:**
- Access modifiers contribute to encapsulation by controlling the visibility of class members, improving code organization and maintainability.

By using `private` and `public` access modifiers appropriately, you can design classes with a clear and controlled interface, enhancing the maintainability and robustness of your TypeScript code.
Loading

0 comments on commit 1f0ca2f

Please sign in to comment.