# Abstraction in TypeScript

Source: https://tpiros.dev/blog/abstraction-in-typescript

Abstraction is an Object Oriented programming concept where a class spells out how an inherited class should implement itself, including any abstract methods.

The idea: we're hiding the complexity of the implementation from inherited classes and letting them fill in the functionality themselves.

In TypeScript, abstraction is achieved with the `abstract` keyword, applied to both classes and methods.

> If you're new to TypeScript classes, read this [introductory article](https://fullstack-developer.academy/classes-in-typescript/) first.

Here's an abstract class with an abstract method:

```typescript
abstract class Warrior {
  readonly name: string;
  public weapon: string;
  constructor(name: string) {
    this.name = name;
  }

  abstract arm(weapon: string): void;
}
```

Try to instantiate this class and we'll get an error:

```typescript
const john = new Warrior('John, the Nomad'); // Cannot create an instance of the abstract class 'Warrior'.
```

To use our abstract class, we need a subclass that extends it with the `extends` keyword. We also need to implement the `arm()` method in that subclass, otherwise TypeScript throws: `Non-abstract class 'SuperWarrior' does not implement inherited abstract member 'arm' from class 'Warrior'.`

```typescript
class SuperWarrior extends Warrior {
  constructor(name: string) {
    super(name);
  }
  arm(weapon: string): void {
    console.log(`${this.name} is a super warrior fighting with ${weapon}`);
  }
}
```

Now we can create our warrior:

```typescript
const warrior = new SuperWarrior('John, the Nomad');
warrior.arm('lance'); // John, the Nomad is a super warrior fighting with lance
```

Since we're writing TypeScript, we can also bolt on Interfaces and implement them for classes. Here's the final code:

```typescript
interface IWarrior {
  name: string;
  weapon: string;
  arm(weapon: string): void;
}
abstract class Warrior implements IWarrior {
  readonly name: string;
  public weapon: string;
  constructor(name: string) {
    this.name = name;
  }

  abstract arm(weapon: string): void;
}

class SuperWarrior extends Warrior {
  constructor(name: string) {
    super(name);
  }
  arm(weapon): void {
    console.log(`${this.name} is a super warrior fighting with ${weapon}`);
  }
}

const warrior: IWarrior = new SuperWarrior('John, the Nomad');
warrior.arm('lance');
```
