Genericos
## Objetivos de Aprendizaje
- Crear funciones genericas
- Definir clases genericas
- Usar interfaces genericas
- Aplicar restricciones de tipo
- Dominar tipos de utilidad
## Por que Genericos?
### Sin Genericos
```typescript
function identity(arg: any): any {
return arg;
}
let num = identity(42); // tipo: any
let str = identity("hola"); // tipo: any
// Informacion de tipo perdida
```
### Con Genericos
```typescript
function identity(arg: T): T {
return arg;
}
let num = identity(42); // tipo: number
let str = identity("hola"); // tipo: string
// Informacion de tipo preservada
```
## Funciones Genericas
### Sintaxis
```typescript
function firstElement(arr: T[]): T | undefined {
return arr[0];
}
let num = firstElement([1, 2, 3]); // number | undefined
let str = firstElement(["a", "b", "c"]); // string | undefined
```
### Multiples Parametros de Tipo
```typescript
function pair(first: T, second: U): [T, U] {
return [first, second];
}
let p = pair("hola", 42); // [string, number]
```
## Interfaces Genericas
### Declaracion
```typescript
interface Container {
value: T;
getValue(): T;
}
class Box implements Container {
constructor(public value: T) {}
getValue(): T {
return this.value;
}
}
let stringBox = new Box("hola");
let numBox = new Box(42);
```
### Interface Generica con Multiples Parametros de Tipo
```typescript
interface Dictionary {
key: T;
value: U;
}
let dict: Dictionary = { key: "edad", value: 30 };
```
## Clases Genericas
### Sintaxis Basica
```typescript
class DataStore {
private data: T[] = [];
add(item: T): void {
this.data.push(item);
}
getAll(): T[] {
return [...this.data];
}
getByIndex(index: number): T | undefined {
return this.data[index];
}
}
let stringStore = new DataStore();
stringStore.add("hola");
stringStore.add("mundo");
```
### Clase Generica con Multiples Parametros de Tipo
```typescript
class Pair {
constructor(
public key: K,
public value: V
) {}
toString(): string {
return `${this.key}: ${this.value}`;
}
}
let pair = new Pair("edad", 30);
pair.toString(); // "edad: 30"
```
## Restricciones de Genericos
### Usando extends
```typescript
interface HasLength {
length: number;
}
function logLength(arg: T): T {
console.log(arg.length);
return arg;
}
logLength("hola"); // 5
logLength([1, 2, 3]); // 3
logLength({ length: 10 }); // 10
// logLength(123); // Error: number no tiene length
```
### Restringir a Claves de Objetos
```typescript
function getProperty(obj: T, key: K): T[K] {
return obj[key];
}
let person = { name: "Alice", age: 30, city: "NYC" };
getProperty(person, "name"); // string
getProperty(person, "age"); // number
// getProperty(person, "foo"); // Error
```
### Multiples Restricciones
```typescript
function compare(
a: T,
b: T
): number {
return a.name.localeCompare(b.name) || a.age - b.age;
}
interface HasName {
name: string;
}
interface HasAge {
age: number;
}
```
## Alias de Tipos Genericos
```typescript
type Result = {
success: boolean;
data?: T;
error?: string;
};
function fetchUser(): Result {
return { success: true, data: user };
}
```
## Parametros de Tipo por Defecto
```typescript
interface Response {
data: T;
status: number;
}
let r1: Response = { data: "OK", status: 200 };
let r2: Response = { data: 42, status: 200 };
```
## Tipos de Utilidad Genericos
### Partial
Todas las propiedades opcionales:
```typescript
interface User {
name: string;
age: number;
}
function updateUser(id: number, updates: Partial): User {
// Combinar actualizaciones con usuario existente
return { ...existingUser, ...updates };
}
```
### Required
Todas las propiedades requeridas:
```typescript
interface Config {
host?: string;
port?: number;
}
let partial: Partial = { host: "localhost" };
let full: Required = { host: "localhost", port: 8080 };
```
### Pick
Seleccionar propiedades:
```typescript
interface User {
id: number;
name: string;
email: string;
age: number;
}
type UserPreview = Pick;
// { id: number; name: string }
```
### Omit
Excluir propiedades:
```typescript
type UserWithoutEmail = Omit;
// { id: number; name: string; age: number }
```
### Record
Crear tipo de objeto:
```typescript
type Role = "admin" | "user" | "guest";
type Permissions = Record;
let perms: Permissions = {
admin: true,
user: false,
guest: true
};
```
### Exclude
Excluir de union:
```typescript
type T = "a" | "b" | "c";
type U = Exclude; // "b" | "c"
```
### Extract
Extraer de union:
```typescript
type T = "a" | "b" | "c";
type U = Extract; // "a" | "b"
```
### NonNullable
Eliminar null y undefined:
```typescript
type T = string | null | undefined;
type U = NonNullable; // string
```
### ReturnType
Obtener tipo de retorno de funcion:
```typescript
function createUser() {
return { name: "Alice", age: 30 };
}
type User = ReturnType;
// { name: string; age: number }
```
### Parameters
Obtener parametros de funcion:
```typescript
function greet(name: string, age: number): string {
return `Hola, ${name}, edad ${age}`;
}
type GreetParams = Parameters;
// [name: string, age: number]
```
## Generico con new()
```typescript
function create(constructor: new () => T): T {
return new constructor();
}
class User {
name: string = "Por defecto";
}
let user = create(User);
```
## Generico en Tipos Condicionales
```typescript
type IsArray = T extends any[] ? true : false;
type A = IsArray; // true
type B = IsArray; // false
```
## Resumen
- Los genericos preservan la informacion de tipo
- `` es el nombre de parametro de tipo mas comun
- Usar `extends` para restringir tipos genericos
- Funciones genericas: `function foo(x: T): T`
- Interfaces genericas: `interface Container`
- Clases genericas: `class Box`
- Tipos de utilidad incorporados: Partial, Pick, Omit, Record
- Usar multiples parametros de tipo: ``
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →