Aula 8

TypeScript

POO (parte 1 - Classe, Objetos, Propriedades, Métodos e Interfaces)

Introdução à Orientação a Objetos com TypeScript

A Programação Orientada a Objetos (POO) organiza o código em entidades chamadas objetos, que encapsulam dados (propriedades) e comportamentos (métodos). Com TypeScript, esse paradigma é fortalecido com a adição de tipagem estática, interfaces e modificadores de acesso, tornando o código mais robusto e legível.

Classe com Tipagem

Uma classe define a estrutura de um objeto. No TypeScript, utilizamos tipos explícitos para garantir segurança e clareza.


class Animal {
  constructor(
    public name: string,
    public species: string
  ) {}

  describe(): string {
    return `${this.name} é um ${this.species}.`;
  }
}
    

Objeto (Instância da Classe)

Um objeto é criado a partir de uma classe usando a palavra-chave new. O TypeScript garante que os valores estejam de acordo com os tipos definidos na classe.


const dog = new Animal('Rex', 'cachorro');
console.log(dog.describe()); // Rex é um cachorro.
    

Propriedades e Métodos com Acessibilidade

Propriedades armazenam valores, enquanto métodos são funções associadas à classe. No TypeScript, usamos public, private e readonly para controlar o acesso e a modificação desses elementos.


class Calculator {
  private history: string[] = [];

  public add(a: number, b: number): number {
    const result = a + b;
    this.log(`${a} + ${b} = ${result}`);
    return result;
  }

  private log(operation: string): void {
    this.history.push(operation);
  }

  public getHistory(): string[] {
    return this.history;
  }
}

const calc = new Calculator();
console.log(calc.add(5, 3)); // 8
console.log(calc.getHistory()); // ['5 + 3 = 8']
    

Interfaces

Interfaces definem a estrutura que uma classe deve seguir. Elas não geram código no JavaScript final, mas ajudam a garantir que certas propriedades e métodos estejam presentes.


interface Describable {
  name: string;
  describe(): string;
}

class Person implements Describable {
  constructor(public name: string, public age: number) {}

  describe(): string {
    return `${this.name} tem ${this.age} anos.`;
  }
}

const user: Describable = new Person('Ana', 28);
console.log(user.describe()); // Ana tem 28 anos.
    

Classes Genéricas

Classes que aceitam tipos genéricos para seus membros, métodos ou propriedades.

Exemplo 1: Classe genérica que armazena um valor


class Storage<T> {
  private _value: T;
  constructor(value: T) {
    this._value = value;
  }
  getValue(): T {
    return this._value;
  }
}
        

Exemplo 2: Classe genérica que representa um par de valores

class Pair<T, U> {
  constructor(public first: T, public second: U) {}
}
        

Exemplo 3: Classe genérica que representa uma pilha (stack)

class Stack<T> {
  private items: T[] = [];
  push(item: T) {
    this.items.push(item);
  }
  pop(): T | undefined {
    return this.items.pop();
  }
}
        

Interfaces Genéricas

Interfaces que definem contratos genéricos, flexíveis para diferentes tipos.

Exemplo 1: Interface genérica para uma função que recebe e retorna o mesmo tipo


interface IdentityFn<T> {
  (arg: T): T;
}
        

Exemplo 2: Interface genérica para um objeto com propriedade data

interface Container<T> {
  data: T;
}
        

Exemplo 3: Interface genérica para uma estrutura que pode armazenar múltiplos tipos

class Stack<T> {
interface KeyValuePair<K, V> {
  key: K;
  value: V;
}}
        

Restrições nos Genéricos

Restrições limitam os tipos genéricos para garantir que eles possuam certas propriedades ou métodos.

Exemplo 1: Restringindo T para tipos que possuem length


function loggingIdentity<T extends { length: number }>(arg: T): T {
  console.log(arg.length);
  return arg;
}}
        

Exemplo 2: Interface para restrição de tipo que deve possuir método toString

interface Stringifiable {
  toString(): string;
}
function printString<T extends Stringifiable>(arg: T): void {
  console.log(arg.toString());
}
        

Exemplo 3: Classe genérica com restrição para tipos que têm método compareTo

interface Comparable {
  compareTo(other: this): number;
}
class SortedCollection<T extends Comparable> {
  private items: T[] = [];
  add(item: T) {
    this.items.push(item);
    this.items.sort((a, b) => a.compareTo(b));
  }
}