Patrones avanzados de TypeScript: genéricos, tipos de utilidad y protectores de tipo
TypeScript Patrones avanzados: genéricos, tipos de utilidad y protectores de tipo
TypeScript ha revolucionado el desarrollo de JavaScript al añadir la escritura estática. Pero para aprovechar realmente su poder, necesitas dominar patrones avanzados. Profundicemos en los genéricos, los tipos de servicios públicos y los protectores de tipo.
Por qué importa el TypeScript avanzado
Escribir TypeScript es fácil. Escribir bueno TypeScript que sea fácil de mantener, seguro y elegante requiere comprender patrones avanzados. Estos patrones te ayudan a:
- 🎯 Capturar errores en el momento de la compilación
- 📚 Mejorar la documentación del código
- 🔄 Permitir una mejor refactorización
- 💡 Mejorar el autocompletado del IDE
Genéricos: escribe una vez, úsalo en todas partes
Los genéricos te permiten escribir código reutilizable que funciona con varios tipos. ### Función genérica básica ```typescript function identity<T>(arg: T): T { return arg; }
const num = identity<number>(42); // type: number
const str = identity<string>("hello"); // type: string
const auto = identity(true); // type inferred: boolean
# ## Restricciones genéricastypescript
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): T { console.log(arg.length); return arg; }
logLength("hello"); // ✅ Works
logLength([1, 2, 3]); // ✅ Works
logLength({ length: 10 }); // ✅ Works
// logLength(42); // ❌ Error: number doesn't have length
# ## Interfaces genéricastypescript
interface Repository<T> {
findById(id: string): Promise<T | null>;
findAll(): Promise<T[]>;
create(item: Omit<T, "id">): Promise<T>;
update(id: string, item: Partial<T>): Promise<T>;
delete(id: string): Promise<void>;
}
interface User { id: string; name: string; email: string; }
class UserRepository implements Repository<User> { async findById(id: string): Promise<User | null> { // Implementation return null; }
async findAll(): Promise<User[]> { return []; }
async create(item: Omit<User, "id">): Promise<User> { const user: User = { id: "generated", ...item }; return user; }
async update(id: string, item: Partial<User>): Promise<User> { // Implementation return { id, name: "", email: "" }; }
async delete(id: string): Promise<void> {
// Implementation
}
}
## Tipos de utilidad: Navaja suiza de TypeScript # ## Parcial<T> - Hacer que todas las propiedades sean opcionalestypescript
interface User {
id: string;
name: string;
email: string;
age: number;
}
function updateUser(id: string, updates: Partial<User>) { // Can update any subset of properties }
updateUser("1", { name: "John" }); // ✅
updateUser("2", { email: "new@email.com" }); // ✅
updateUser("3", { name: "Jane", age: 30 }); // ✅
### Seleccionar<T, K> - Seleccionar propiedades específicastypescript
type UserPreview = Pick<User, "id" | "name">;
const preview: UserPreview = {
id: "1",
name: "John"
// email and age not required
};
# ## Omitir<T, K> - Excluir propiedades específicastypescript
type UserCreate = Omit<User, "id">;
const newUser: UserCreate = {
name: "John",
email: "john@example.com",
age: 30
// id is excluded
};
# ## Registrar<K, T> - Crear tipo de objeto con claves específicastypescript
type Role = "admin" | "user" | "guest";
type Permissions = Record<Role, string[]>;
const permissions: Permissions = {
admin: ["read", "write", "delete"],
user: ["read", "write"],
guest: ["read"]
};
# ## Tipo de devolución<T> - Tipo de devolución de función de extraccióntypescript
function createUser() {
return {
id: "123",
name: "John",
email: "john@example.com"
};
}
type User = ReturnType<typeof createUser>;
// type User = { id: string; name: string; email: string; }
## Protecciones de tipo: seguridad de tipo de tiempo de ejecución ## # typeof Type Guard __CODE_BLOCK_8 __ ## # instancia de Type Guard __ CODE_BLOCK_9 __ ## # Protecciones de tipo personalizadas __ CODE_BLOCK_10 __ ## # Uniones discriminadas __ CODE_BLOCK_11__ ## Patrón avanzado: tipos condicionalestypescript
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true type B = IsString<number>; // false
// More practical example type NonNullable<T> = T extends null | undefined ? never : T;
type A = NonNullable<string | null>; // string
type B = NonNullable<number | undefined>; // number
## Patrón avanzado: tipos mapeadostypescript
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Optional<T> = { [P in keyof T]?: T[P]; };
interface User { id: string; name: string; }
type ReadonlyUser = Readonly<User>; // { readonly id: string; readonly name: string; }
type OptionalUser = Optional<User>;
// { id?: string; name?: string; }
## Ejemplo real: manipulador de respuesta APItypescript
interface ApiResponse<T> {
data?: T;
error?: string;
status: number;
}
// Generic fetch wrapper async function fetchApi<T>(url: string): Promise<ApiResponse<T>> { try { const response = await fetch(url); const data = await response.json();
return {
data,
status: response.status
};
} catch (error) { return { error: error instanceof Error ? error.message : "Unknown error", status: 500 }; } }
// Type-safe usage interface User { id: string; name: string; }
async function getUser(id: string) {
const response = await fetchApi<User>(/api/users/${id});
if (response.error) { console.error(response.error); return null; }
return response.data; // TypeScript knows this is User | undefined }
2. **Aprovecha los tipos de utilidad **: no reinventes la rueda
3. **Crear protectores de tipo personalizados **: mejorar la seguridad del tipo de tiempo de ejecución
4. **Usar sindicatos discriminados **: para una gestión estatal compleja
5. **Mantenga los tipos simples**: no haga demasiada ingeniería
## Errores comunes a evitar
❌ **Demasiado genérico**
```typescript
function process<T>(data: T): T {
// Too generic, loses type information
return data;
}
✅ ** Restringido correctamente **
Loading code...
Conclusión
Los patrones avanzados de TypeScript transforman tu código de "JavaScript escrito" a aplicaciones verdaderamente seguras y mantenibles. Domina estos patrones y escribirás mejor el código con menos errores.
Comience poco a poco, practique a menudo e incorpore gradualmente estos patrones en sus proyectos . ¡Tu futuro yo (y tus compañeros de equipo) te lo agradecerán! 🚀