Lições do módulo (2/2)
Genéricos Fundamentais
Genéricos (programação genérica) são um dos recursos mais poderosos do TypeScript. Eles permitem que você escreva componentes, funções e interfaces flexíveis e reutilizáveis que podem funcionar com diferentes tipos de dados, mantendo a máxima segurança de tipo e evitando o uso de any.
Funções genéricas
Pense em um genérico como uma variável para tipos. Vamos considerar uma função que retorna o valor passado a ela como argumento:
function identity<T>(arg: T): T {
return arg;
}A letra T (abreviação de Type) é um espaço reservado para o tipo. Quando chamamos identity, o TypeScript captura o tipo do argumento passado e define automaticamente T para esse tipo:
const str = identity<string>('Hello'); // T is string
const num = identity(42); // T is number (automatically inferred!)Interfaces genéricas e aliases
Os genéricos também podem ser aplicados a interfaces e aliases de tipo para definir contêineres genéricos ou estruturas de dados:
interface Box<T> {
content: T;
}
const stringBox: Box<string> = { content: 'TypeScript' };
const numberBox: Box<number> = { content: 42 };Vários parâmetros de tipo
Podemos definir funções ou tipos que usam variáveis de vários tipos (por exemplo, T e U):
function mergeObjects<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}Restrições genéricas
Às vezes queremos limitar os tipos aceitos por um genérico. Podemos usar a palavra-chave extends para adicionar uma restrição.
Por exemplo, se quisermos que o tipo genérico sempre tenha uma propriedade length (como strings ou arrays):
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(arg: T): void {
console.log(arg.length); // Safe! We know arg has 'length'
}
logLength('Hello'); // Valid
logLength([1, 2, 3]); // Valid
// logLength(42); // Error: number does not have a length property!Experimente você mesmo
Exercício 1: Função de Identidade Genérica
Complete a função de identidade genérica para que ela aceite um parâmetro de valor do tipo genérico T e o retorne sem modificação.
Mostrar dica
O tipo de retorno deve ser o mesmo tipo genérico T do parâmetro.
Solução disponível após 3 tentativas
Exercício 2: Wrapper de caixa genérico
Defina uma interface genérica chamada Box que aceita um parâmetro de tipo T e possui uma única propriedade chamada content do tipo T.
Mostrar dica
Use a interface Box<T> { content: T; } sintaxe.
Solução disponível após 3 tentativas
Exercício 3: Restrição Genérica
Escreva uma função genérica chamada getLength que aceite um parâmetro arg. arg deve ser restrito a uma interface que possui uma propriedade length (número). A função deve retornar arg.length.
Mostrar dica
Declare a função como getLength<T extends HasLength>(arg: T): number e retorne arg.length.
Solução disponível após 3 tentativas
Exercício 4: Par Genérico
Defina uma interface genérica Pair<T, U> com duas propriedades: a primeira do tipo T e a segunda do tipo U. Em seguida, crie uma função genérica makePair que aceita a primeira (do tipo T) e a segunda (do tipo U) e retorna um objeto implementando Pair<T, U>.
Mostrar dica
Use a sintaxe para dois parâmetros genéricos Pair<T, U> e defina makePair adequadamente.
Solução disponível após 3 tentativas