Genéricos em TypeScript
Este artigo explica genéricos em TypeScript.
YouTube Video
Genéricos em TypeScript
Genéricos em TypeScript são um recurso que permite definir funções, classes e interfaces reutilizáveis e seguras quanto ao tipo ao parametrizar os tipos. Ao usar genéricos, você pode escrever código que não depende de tipos específicos, permitindo realizar as mesmas operações em diversos tipos.
Noções básicas sobre Genéricos
Genéricos funcionam como templates que aceitam tipos como argumentos, permitindo que funções e classes lidem com diferentes tipos.
Funções Genéricas
A seguir está um exemplo de função com seus tipos de argumentos especificados usando genéricos.
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity<number>(42)); // 42
6console.log(identity<string>("Hello")); // Hello
T
é um argumento de tipo genérico que representa os tipos dos argumentos e do valor de retorno da função. O tipo real é determinado quando a função é chamada.- Ao especificar explicitamente
<number>
ou<string>
, você está determinando o tipo.
Tipos genéricos funcionam sem especificação explícita porque o TypeScript faz inferência de tipos.
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity(42)); // 42
6console.log(identity("Hello")); // Hello
Restrições em Genéricos
Ao impor restrições nos genéricos, você pode limitar para que aceitem apenas tipos específicos.
1function loggingIdentity<T extends { length: number }>(arg: T): T {
2 console.log(arg.length);
3 return arg;
4}
5
6loggingIdentity("Hello"); // 5
7loggingIdentity([1, 2, 3]); // 3
8
9// loggingIdentity(42); // Error: number does not have a length property.
- Ao especificar
T extends { length: number }
, estamos indicando queT
deve ser um tipo que possui a propriedadelength
. Portanto, tipos sem a propriedadelength
não serão aceitos.
Classes Genéricas
Classes também podem ser definidas usando genéricos. Classes genéricas oferecem tipos flexíveis para propriedades e métodos.
1class Box<T> {
2 private _value: T;
3
4 constructor(value: T) {
5 this._value = value;
6 }
7
8 public getValue(): T {
9 return this._value;
10 }
11
12 public setValue(value: T): void {
13 this._value = value;
14 }
15}
16
17const numberBox = new Box<number>(100);
18console.log(numberBox.getValue()); // 100
19
20const stringBox = new Box<string>("Hello");
21console.log(stringBox.getValue()); // Hello
Box<T>
declara o tipoT
usado dentro da classe como genérico. Isso permite que a mesma classe seja reutilizada para diferentes tipos.
Interfaces Genéricas
Genéricos também podem ser usados com interfaces.
1interface Pair<T, U> {
2 first: T;
3 second: U;
4}
5
6const numberStringPair: Pair<number, string> = { first: 1, second: "One" };
7console.log(numberStringPair); // { first: 1, second: 'One' }
8
9const booleanArrayPair: Pair<boolean, number[]> = { first: true, second: [1, 2, 3] };
10console.log(booleanArrayPair); // { first: true, second: [ 1, 2, 3 ] }
- Ao especificar dois tipos genéricos com
Pair<T, U>
, você pode definir um objeto com uma combinação de diferentes tipos.
Argumentos de Tipo Padrão
Também é possível especificar um tipo padrão para os argumentos genéricos.
1function createArray<T = string>(length: number, value: T): T[] {
2 return Array(length).fill(value);
3}
4
5console.log(createArray(3, "a")); // ['a', 'a', 'a']
6console.log(createArray(3, 100)); // [100, 100, 100]
- Estamos definindo o argumento de tipo padrão como
string
com<T = string>
. Se nenhum tipo for especificado explicitamente,T
será do tipostring
.
Apelidos de Tipos Genéricos
Genéricos também podem ser usados como apelidos de tipo (type
).
1type Result<T> = {
2 success: boolean;
3 data: T;
4};
5
6const successResult: Result<number> = { success: true, data: 42 };
7const errorResult: Result<string> = { success: false, data: "Error occurred" };
8
9console.log(successResult); // { success: true, data: 42 }
10console.log(errorResult); // { success: false, data: 'Error occurred' }
Result<T>
representa um objeto resultado que contém dados do tipoT
. Dessa forma, você pode criar apelidos de tipo flexíveis usando genéricos.
Múltiplos Tipos Genéricos
Ao usar múltiplos tipos genéricos, você pode definir funções e classes ainda mais versáteis.
1function merge<T, U>(obj1: T, obj2: U): T & U {
2 return { ...obj1, ...obj2 };
3}
4
5const person = { name: "Alice" };
6const job = { title: "Engineer" };
7
8const merged = merge(person, job);
9console.log(merged); // { name: 'Alice', title: 'Engineer' }
- A função
merge
recebe dois tipos diferentes,T
eU
, e os combina para retornar um novo objeto.
Resumo
- Genéricos permitem código reutilizável e seguro em relação a tipos, tratando tipos como parâmetros.
- Ao usar genéricos em funções, classes e interfaces, é possível escrever lógica flexível que trata diversos tipos.
- Ao adicionar restrições aos argumentos de tipo ou definir argumentos de tipo padrão, você pode controlar o escopo dos genéricos.
Ao usar genéricos, você pode escrever código independente de tipo e de uso geral, aproveitando ao máximo o poderoso sistema de tipos do TypeScript.
Você pode acompanhar o artigo acima usando o Visual Studio Code em nosso canal do YouTube. Por favor, confira também o canal do YouTube.