Transitioning to TypeScript: The Ultimate Starter Guide - Part 2
Tags: typescript, javascript, webdev, programming
Published: 2023-08-29 05:24:56

## TypeScript from JavaScript: A Comprehensive Guide - Part 2 of 7

Hello again, future TypeScript pros! 🌟

In the first part of this series, we introduced you to the basics of TypeScript, its advantages over JavaScript, and how to set up a TypeScript project. In this second part, we will dive deeper into TypeScript's type system and learn about more advanced features like interfaces, classes, and generics. Let's get started!

## Table of Contents

1. Recap
2. Interfaces in TypeScript
3. Classes in TypeScript
4. Generics in TypeScript
5. Conclusion

## 1. Recap

In the first part of this series, we learned about some basic types in TypeScript like `number`, `string`, `boolean`, `array`, `tuple`, `enum`, `any`, and `void`. We also learned how to set up a TypeScript project and compile TypeScript code into JavaScript.

## 2. Interfaces in TypeScript

Interfaces are a powerful way to define contracts within your code and contracts with code outside of your project. They are used to define the shape of an object, i.e., the properties and methods that an object should have.

### a. Defining Interfaces

You can define an interface using the `interface` keyword followed by the interface name. Here is an example of a simple interface:

```typescript
interface Person {
  firstName: string;
  lastName: string;
}
```

In this example, the `Person` interface has two properties: `firstName` and `lastName`, both of which are of type `string`.

### b. Implementing Interfaces

Once you have defined an interface, you can use it as a type for your variables, parameters, or return values. Here is an example:

```typescript
function greet(person: Person) {
  return `Hello, ${person.firstName} ${person.lastName}`;
}

const john: Person = {
  firstName: 'John',
  lastName: 'Doe',
};

console.log(greet(john)); // Hello, John Doe
```

In this example, the `greet` function expects a `Person` object as its parameter. The `john` object is of type `Person`, so it can be passed to the `greet` function.

### c. Optional Properties

Interfaces can also have optional properties. You can mark a property as optional by adding a `?` after its name. Here is an example:

```typescript
interface Person {
  firstName: string;
  lastName: string;
  middleName?: string;
}

const john: Person = {
  firstName: 'John',
  lastName: 'Doe',
};

const jane: Person = {
  firstName: 'Jane',
  lastName: 'Doe',
  middleName: 'Mary',
};
```

In this example, the `middleName` property is optional. The `john` object does not have a `middleName` property, and that's fine. The `jane` object has a `middleName` property, and that's fine too.

### d. Read-Only Properties

Interfaces can also have read-only properties. You can mark a property as read-only by adding the `readonly` keyword before its name. Here is an example:

```typescript
interface Person {
  readonly id: number;
  firstName: string;
  lastName: string;
}

const john: Person = {
  id: 1,
  firstName: 'John',
  lastName: 'Doe',
};

john.id = 2; // Error: Cannot assign to 'id' because it is a read-only property
```

In this example, the `id` property is read-only. Trying to modify it after its initial assignment will result in a compile-time error.

## 3. Classes in TypeScript

Classes in TypeScript are similar to classes in other object-oriented programming languages. They are used to define the blueprint for creating objects.

### a. Defining Classes

You can define a class using the `class` keyword followed by the class name. Here is an example of a simple class:

```typescript
class Car {
  brand: string;
  model: string;
  year: number;

  constructor(brand: string, model: string, year: number) {
    this.brand = brand;
    this.model = model;
    this.year = year;
  }

  start() {
    console.log('Car started');
  }

  drive() {
    console.log('Car is driving');
  }
}
```

In this example, the `Car` class has three properties: `brand`, `model`, and `year`, and three methods: `constructor`, `start`, and `drive`.

### b. Creating Objects

Once you have defined a class, you can create objects of that class using the `new` keyword. Here is an example:

```typescript
const myCar = new Car('Toyota', 'Corolla', 2020);

myCar.start();
myCar.drive();
```

In this example, a new `Car` object is created with the `brand`, `model`, and `year` properties set to `'Toyota'`, `'Corolla'`, and `2020`, respectively. The `start` and `drive` methods are then called on the `myCar` object.

### c. Access Modifiers

TypeScript supports three access modifiers: `public`, `private`, and

 `protected`.

- `public`: This is the default modifier and can be accessed anywhere.
- `private`: This can only be accessed within the class where it is defined.
- `protected`: This can be accessed within the class where it is defined and in any subclass of that class.

Here is an example:

```typescript
class Car {
  public brand: string;
  private model: string;
  protected year: number;

  constructor(brand: string, model: string, year: number) {
    this.brand = brand;
    this.model = model;
    this.year = year;
  }
}

const myCar = new Car('Toyota', 'Corolla', 2020);

console.log(myCar.brand); // Toyota
console.log(myCar.model); // Error: Property 'model' is private and only accessible within class 'Car'
console.log(myCar.year); // Error: Property 'year' is protected and only accessible within class 'Car' and its subclasses
```

In this example, the `brand` property can be accessed outside of the `Car` class because it is `public`. The `model` and `year` properties cannot be accessed outside of the `Car` class because they are `private` and `protected`, respectively.

### d. Inheritance

Classes in TypeScript can inherit properties and methods from other classes. This is done using the `extends` keyword. Here is an example:

```typescript
class ElectricCar extends Car {
  range: number;

  constructor(brand: string, model: string, year: number, range: number) {
    super(brand, model, year);
    this.range = range;
  }

  charge() {
    console.log('Car is charging');
  }
}

const myElectricCar = new ElectricCar('Tesla', 'Model 3', 2020, 500);

myElectricCar.start();
myElectricCar.drive();
myElectricCar.charge();
```

In this example, the `ElectricCar` class extends the `Car` class and inherits its properties and methods. It also adds a new property, `range`, and a new method, `charge`.

## 4. Generics in TypeScript

Generics are a way to create reusable components that work with any type. They are similar to templates in other programming languages.

### a. Generic Functions

You can create generic functions by using a type variable, which is a special kind of variable that works on types rather than values. Here is an example:

```typescript
function identity<T>(arg: T): T {
  return arg;
}

const myNumber = identity<number>(5);
const myString = identity<string>('Hello');

console.log(myNumber); // 5
console.log(myString); // Hello
```

In this example, the `identity` function is a generic function that takes an argument `arg` of type `T` and returns a value of type `T`. The `myNumber` and `myString` variables are created by calling the `identity` function with `<number>` and `<string>` type arguments, respectively.

### b. Generic Classes

You can also create generic classes by using a type variable. Here is an example:

```typescript
class ArrayOfNumbers {
  private items: number[];

  constructor() {
    this.items = [];
  }

  add(item: number) {
    this.items.push(item);
  }

  getItems() {
    return this.items;
  }
}

const numbers = new ArrayOfNumbers();
numbers.add(1);
numbers.add(2);
numbers.add(3);
console.log(numbers.getItems()); // [1, 2, 3]

class ArrayOfStrings {
  private items: string[];

  constructor() {
    this.items = [];
  }

  add(item: string) {
    this.items.push(item);
  }

  getItems() {
    return this.items;
  }
}

const strings = new ArrayOfStrings();
strings.add('a');
strings.add('b');
strings.add('c');
console.log(strings.getItems()); // ['a', 'b', 'c']
```

In this example, the `ArrayOfNumbers` and `ArrayOfStrings` classes are not generic, and therefore, you need to create two separate classes for handling arrays of `number` and `string` items. This is not very efficient.

Here is how you can use generics to create a single `Array` class that can handle arrays of any type:

```typescript
class Array<T> {
  private items: T[];

  constructor() {
    this.items = [];
  }

  add(item: T) {
    this.items.push(item);
  }

  getItems() {
    return this.items;
  }
}

const numbers = new Array<number>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
console.log(numbers.getItems()); // [1, 2, 3]

const strings = new Array<string>();
strings.add('a');
strings.add('b');
strings.add('c');
console.log(strings.getItems()); // ['a', 'b', 'c']
```

In this example, the `Array` class is a generic class that takes a type argument `T`. The `numbers` and `strings` variables are created by calling the `Array` class with `<number>` and `<string>` type arguments, respectively.

## 5. Conclusion

Congrats! 🎉 You have successfully learned about interfaces, classes, and generics in TypeScript. These are some of the most powerful features of TypeScript and will help you write more robust

 and reusable code.

In the next part of this series, we will learn about modules, namespaces, and decorators in TypeScript. Stay tuned!

That's all for now, happy coding! 💻✨

---

If you are just joining in, here are the links to the other parts of this series:

1. [TypeScript from JavaScript Part 1: Introduction and Basic Types](https://dev.to/innovatesphere/transitioning-to-typescript-the-ultimate-starter-guide-part-1-2he5)

---

That’s a wrap. Thanks for reading.

If you're looking for more premium content and resources to help you start and grow your business, consider subscribing to my [Newsletter](https://innovatesphere.beehiiv.com/).

Want to see what I am working on? Check out my [Twitter](https://twitter.com/abhaysinghr1)