Genéricos avançados do TypeScript explicados com exemplos
Genéricos em TypeScript fornecem uma maneira de criar componentes de código reutilizáveis e flexíveis trabalhando com uma variedade de tipos de dados. Genéricos avançados levam esse conceito mais adiante ao introduzir recursos adicionais como restrições, valores padrão e vários tipos, que permitem que os desenvolvedores escrevam códigos mais robustos e seguros para tipos. Neste artigo, exemplos serão usados para explorar esses conceitos avançados em genéricos.
Restrições genéricas
Restrições limitam os tipos que um genérico pode aceitar. Isso garante que o tipo passado para uma função ou classe genérica atenda a certos critérios. Por exemplo, uma restrição pode ser usada para garantir que o tipo genérico tenha uma propriedade ou método específico.
function getLength<T extends { length: number }>(arg: T): number {
return arg.length;
}
const stringLength = getLength("TypeScript");
const arrayLength = getLength([1, 2, 3]);
Neste exemplo, a restrição <T extends { length: number }>
garante que o argumento passado para getLength
tenha uma propriedade length
.
Vários Genéricos
TypeScript permite o uso de vários tipos genéricos na mesma função, classe ou interface. Isso é útil ao trabalhar com pares de valores ou outras estruturas de dados envolvendo vários tipos.
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
const stringNumberPair = pair("TypeScript", 2024);
Esta função, pair
, aceita dois tipos genéricos diferentes, T
e U
, e retorna uma tupla contendo ambos os tipos.
Tipos genéricos padrão
Genéricos em TypeScript também podem ter tipos padrão. Isso é útil quando você quer que um genérico tenha um tipo de fallback se nenhum tipo específico for fornecido.
function identity<T = string>(value: T): T {
return value;
}
const defaultString = identity("Hello"); // T is string
const customNumber = identity<number>(100); // T is number
Neste exemplo, se nenhum tipo for passado para identity
, o padrão será string
.
Usando Genéricos com Interfaces
Genéricos podem ser usados com interfaces para definir estruturas complexas onde os tipos não são fixos. Isso adiciona flexibilidade a como os dados são gerenciados.
interface Container<T> {
value: T;
}
const stringContainer: Container<string> = { value: "Hello" };
const numberContainer: Container<number> = { value: 42 };
A interface Container
foi projetada para armazenar um valor de qualquer tipo, permitindo diferentes tipos de contêineres com tipos específicos.
Classes genéricas
Classes em TypeScript também podem ser genéricas. Isso é especialmente útil ao projetar classes que funcionam com vários tipos de dados, como classes de armazenamento ou coleção de dados.
class DataStore<T> {
private data: T[] = [];
add(item: T): void {
this.data.push(item);
}
getAll(): T[] {
return this.data;
}
}
const stringStore = new DataStore<string>();
stringStore.add("Hello");
stringStore.add("TypeScript");
const numberStore = new DataStore<number>();
numberStore.add(42);
Neste exemplo, a classe DataStore
funciona com qualquer tipo de dado, fornecendo uma maneira segura de armazenar e recuperar elementos.
Conclusão
Genéricos avançados em TypeScript são uma ferramenta poderosa para escrever código flexível, reutilizável e com segurança de tipo. Ao usar restrições, vários tipos, valores padrão e genéricos em classes e interfaces, os desenvolvedores podem escrever código mais complexo e robusto. Entender e utilizar esses conceitos avançados permite maior flexibilidade e garante a segurança de tipo em todos os aplicativos.