Ответ
Generics (обобщенные типы) в TypeScript — это механизм для создания компонентов, которые могут работать с различными типами данных, сохраняя при этом строгую типизацию. В Node.js разработке это особенно полезно для создания переиспользуемых сервисов, репозиториев и утилит.
Базовый пример с функцией:
// Обобщенная функция для логирования любого типа данных
function logData<T>(data: T): void {
console.log(`[${new Date().toISOString()}]`, data);
}
logData<string>('User logged in');
logData<number>(404);
logData<{ id: number; name: string }>({ id: 1, name: 'John' });
Практическое применение в Node.js:
- Обобщенные репозитории для работы с БД:
interface Repository<T> { findById(id: string): Promise<T | null>; save(entity: T): Promise<T>; delete(id: string): Promise<boolean>; }
class BaseRepository
async findById(id: string): Promise<T | null> { return this.model.findById(id); }
async save(entity: T): Promise
// Использование interface IUser { id: string; email: string; name: string; }
const userRepository = new BaseRepository
2. **Обобщенные сервисы:**
```typescript
class CacheService<T> {
private cache = new Map<string, T>();
set(key: string, value: T): void {
this.cache.set(key, value);
}
get(key: string): T | undefined {
return this.cache.get(key);
}
// Использование с ограничениями (constraints)
getAllByType<U extends T>(typeGuard: (item: T) => item is U): U[] {
return Array.from(this.cache.values()).filter(typeGuard);
}
}
// Использование
const userCache = new CacheService<{ id: string; name: string }>();
userCache.set('user1', { id: '1', name: 'Alice' });
- Обобщенные middleware в Express:
function validateBody<T>(schema: Joi.Schema<T>): RequestHandler { return (req, res, next) => { const { error, value } = schema.validate(req.body); if (error) { return res.status(400).json({ error: error.message }); } req.validatedBody = value as T; next(); }; }
// Использование interface LoginDto { email: string; password: string; }
app.post('/login', validateBody
**Преимущества в Node.js контексте:**
- Повторное использование кода для разных сущностей
- Автодополнение и проверка типов в IDE
- Безопасность типов при работе с внешними API и базами данных
- Улучшенная читаемость и поддерживаемость кода Ответ 18+ 🔞
Слушай, ну это ж просто пиздец как круто, когда можно один раз написать код, а потом подсовывать ему любые типы, и он не охуевает! Generics в TypeScript — это как универсальная отвертка, которая подходит и под крестик, и под плоский, и под звёздочку. В Node.js без них — просто караул, блядь, особенно когда пишешь сервисы или работаешь с базой.
Смотри, самый простой пример, чтобы въехать:
// Функция, которая может принять что угодно и залогировать
function logData<T>(data: T): void {
console.log(`[${new Date().toISOString()}]`, data);
}
// И ей похуй, что ты туда суёшь — строку, число или объект
logData<string>('Юзер зашёл');
logData<number>(404);
logData<{ id: number; name: string }>({ id: 1, name: 'Васян' });
Вот видишь? Одна функция, а работает со всем. Красота, ёпта!
А теперь где это реально вкатывает в Node.js:
- Репозитории для базы данных — просто песня! Раньше для каждой сущности (User, Product, Order) надо было писать свой репозиторий, копипастить одни и те же методы. А теперь? Овердохуища удобства!
// Объявляем интерфейс, что должен уметь любой репозиторий
interface Repository<T> {
findById(id: string): Promise<T | null>;
save(entity: T): Promise<T>;
delete(id: string): Promise<boolean>;
}
// Пишем ОДИН базовый класс на все случаи жизни
class BaseRepository<T> implements Repository<T> {
constructor(private model: any) {}
async findById(id: string): Promise<T | null> {
return this.model.findById(id);
}
async save(entity: T): Promise<T> {
return this.model.create(entity);
}
}
// А теперь используем. Создаём тип для юзера...
interface IUser {
id: string;
email: string;
name: string;
}
// ...и на раз-два делаем репозиторий именно для него!
const userRepository = new BaseRepository<IUser>(UserModel);
// Всё! findById и save уже будут знать, что работают с IUser. Автодополнение в IDE ликует, доверия ебать ноль к ошибкам.
- Сервис кэширования — тоже хитрая жопа получается. Хочешь кэшировать строки? Пожалуйста. Хочешь целые объекты? Да похуй, главное тип указать.
class CacheService<T> {
private cache = new Map<string, T>();
set(key: string, value: T): void {
this.cache.set(key, value);
}
get(key: string): T | undefined {
return this.cache.get(key);
}
// А вот это вообще магия: можно фильтровать закэшированное по типу!
getAllByType<U extends T>(typeGuard: (item: T) => item is U): U[] {
return Array.from(this.cache.values()).filter(typeGuard);
}
}
// Используем для пользователей
const userCache = new CacheService<{ id: string; name: string }>();
userCache.set('user1', { id: '1', name: 'Алиса' });
// Теперь userCache.get() будет возвращать именно объект с id и name, а не какую-то хуйню.
- Middleware в Express — тут вообще без generics жить невозможно.
Валидация тела запроса — типичная задача. Раньше после валидации в
req.bodyбылany, и можно было накосячить. А теперь...
function validateBody<T>(schema: Joi.Schema<T>): RequestHandler {
return (req, res, next) => {
const { error, value } = schema.validate(req.body);
if (error) {
return res.status(400).json({ error: error.message });
}
// Вот тут магия! Говорим TypeScript: "поверь, это тип T".
req.validatedBody = value as T;
next();
};
}
// Объявляем, что ждём на вход в /login
interface LoginDto {
email: string;
password: string;
}
// И вуаля! В контроллере в req.validatedBody будет строго LoginDto
app.post('/login', validateBody<LoginDto>(loginSchema), loginController);
Итог, чувак: Писать без generics в TypeScript на Node.js — это как ехать на Ferrari, но на первой передаче. Преимущества — просто удивление пиздец:
- Переиспользование кода: Один раз написал
BaseRepository— и на все сущности хватит. - Безопасность и автодополнение: IDE не позволит тебе сохранить в базу поля, которых нет в типе. Спасёт от тупых ошибок в рантайме.
- Читаемость: Сразу видно, с чем работает функция или класс. Не надо гадать, что там за
data: anyприлетело.
Короче, generics — это не просто фича языка, это must have для любого адекватного бэкенда на TypeScript. Осваивай и не бзди!
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶