Explorando Generics no TypeScript
typescript

No TypeScript, Generics oferecem uma maneira poderosa de criar componentes reutilizáveis e flexíveis. No entanto, entender a lógica por trás dos Generics é fundamental para aproveitar ao máximo essa funcionalidade. Vamos explorar em detalhes como Generics funcionam, de que maneira eles trazem flexibilidade ao código, e como a lógica de Generics permite a criação de código seguro e robusto.

O Que São Generics?

Em linguagens de programação, a reutilização de código é essencial. E, Generics são um recurso que permite que funções, classes e interfaces operem em múltiplos tipos sem perder a segurança de tipos. A ideia principal é que você pode definir um bloco de código que funcione para qualquer tipo, especificando esse tipo apenas quando necessário.

Lógica Por Trás dos Generics

A lógica dos Generics se baseia na capacidade de atrasar a especificação do tipo até que o código seja utilizado. Diferentemente de linguagens de programação que forçam a escolha do tipo antecipadamente (estaticamente tipadas), o TypeScript permite a criação de componentes que podem operar com diferentes tipos conforme a necessidade.

Bora entender 👇

Funções Genéricas: Como Elas Funcionam

Funções genéricas são uma forma de definir funções que podem trabalhar com diferentes tipos de entrada e saída. A função genérica aceita um parâmetro de tipo que especifica o tipo de dado que a função irá processar.

function identity<T>(arg: T): T {
  return arg;
}
A visual depiction of what is being written about

Entendendo a lógica no passo a passo:

1. Definição de Tipo Genérico (<T>): Quando escrevemos <T>, estamos definindo um parâmetro de tipo genérico. O T é um marcador que representa qualquer tipo.

2. Aplicação do Tipo Genérico: Dentro da função, T é usado como tipo de arg (argumento) e também como tipo de retorno. Isso significa que qualquer tipo passado para a função será o mesmo tipo retornado.

3. Inferência de Tipo: Quando chamamos a função identity sem especificar o tipo, o TypeScript infere o tipo de T com base no valor fornecido:

Se liga 👇

let output1 = identity("Hello, TypeScript!"); // T é 'string'

Essa inferência de tipo é o que permite que a função genérica seja tão flexível e reutilizável.

A visual depiction of what is being written about

Bora codar juntos um gerenciador de metas?

embarcar na missão

Agora que você entendeu, bora continuar 👇

Classes Genéricas: Flexibilidade na Criação de Estruturas de Dados

Classes genéricas permitem criar estruturas de dados que podem ser reutilizadas com diferentes tipos de dados. A lógica por trás das classes genéricas é semelhante à das funções: um tipo genérico é usado para representar os dados que a classe manipula.

class Box<T> {
  contents: T;

  constructor(contents: T) {
    this.contents = contents;
  }

  getContents(): T {
    return this.contents;
  }
}
Entendendo a Lógica:

1. Parâmetro de Tipo <T>: Assim como nas funções, <T> é um marcador que indica que Box é genérico e pode armazenar qualquer tipo.

2. Uso Consistente de T: O parâmetro de tipo T é usado para definir o tipo da propriedade contents e o tipo de retorno do método getContents. Isso garante que o tipo especificado ao instanciar a classe seja consistente em toda a classe.

3. Polimorfismo Paramétrico: O TypeScript permite criar várias instâncias de Box com diferentes tipos, sem a necessidade de reescrever a classe.

const stringBox = new Box<string>("TypeScript");
const numberBox = new Box<number>(100);

Interfaces Genéricas: Definindo Contratos Flexíveis

Interfaces genéricas são úteis para definir contratos flexíveis que podem ser adaptados a diferentes tipos de dados. Isso é especialmente útil ao trabalhar com funções que aceitam e retornam o mesmo tipo de dado.

interface GenericIdentityFn<T> {
  (arg: T): T;
}
Entendendo a Lógica:

1. Uso do Parâmetro de Tipo em Interfaces: Ao declarar uma interface genérica, você permite que diferentes implementações sejam criadas com base no tipo especificado pelo usuário da interface.

2. Segurança de Tipos Dinâmica: A interface GenericIdentityFn define um contrato para funções que aceitam um argumento de tipo T e retornam o mesmo tipo T. Isso evita a criação de funções que aceitem um tipo de dado e retornem outro, aumentando a segurança de tipos.

Restrições de Tipo com Generics (Type Constraints)

Às vezes, queremos restringir os tipos que um parâmetro genérico pode aceitar. Por exemplo, podemos querer que o tipo tenha uma propriedade específica.

Bora codar juntos um gerenciador de metas?

embarcar na missão
function loggingIdentity<T extends { length: number }>(arg: T): T {
  console.log(arg.length);
  return arg;
}
Entendendo a Lógica:

1. Definição de Restrições (extends): Usando extends, estamos restringindo o tipo T para que ele herde de um tipo que tem uma propriedade length. Isso garante que arg.length seja válido.

2. Segurança de Tipo Aprimorada: Esta restrição permite ao TypeScript fornecer autocompletar e validação ao acessar a propriedade length de arg.

3. Uso Prático: Isso é útil quando queremos permitir que a função aceite apenas tipos que têm uma propriedade length, como strings, arrays ou outros objetos personalizados.

A visual depiction of what is being written about

Combinando Generics com Outras Funcionalidades do TypeScript

Uma das combinações poderosas é o uso de Generics com keyof, permitindo criar funções que trabalham com chaves de objetos de maneira segura.

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
Entendendo a Lógica:

1. Combinação de keyof e Generics: K extends keyof T significa que K deve ser uma das chaves de T. Isto permite que a função acesse propriedades de um objeto de forma segura.

2. Retorno de Tipo Preciso: O tipo de retorno é T[K], que é o tipo da propriedade key no objeto obj. Isso oferece uma segurança de tipo ainda maior e reduz a probabilidade de erros.

Os Generics no TypeScript são uma ferramenta poderosa que oferece flexibilidade e segurança de tipos para desenvolvedores. Ao entender a lógica por trás de como os Generics funcionam e como eles podem ser combinados com outras funcionalidades do TypeScript, você pode escrever código que não apenas é reutilizável e eficiente, mas também é robusto e seguro.

Se você deseja criar componentes reutilizáveis, seguros e fáceis de manter em seus projetos TypeScript, os Generics são um recurso essencial para dominar.

Bora codar juntos um gerenciador de metas?

embarcar na missão

Aprenda programação do zero e DE GRAÇA

No Discover você vai descomplicar a programação, aprender a criar seu primeiro site com a mão na massa e iniciar sua transição de carreira.

COMECE A ESTUDAR AGORA