Что такое Generics в TypeScript и как их использовать в Node.js проектах?

«Что такое Generics в TypeScript и как их использовать в Node.js проектах?» — вопрос из категории TypeScript, который задают на 26% собеседований Node.js Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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:

  1. Обобщенные репозитории для работы с БД:
    
    interface Repository<T> {
    findById(id: string): Promise<T | null>;
    save(entity: T): Promise<T>;
    delete(id: string): Promise<boolean>;
    }

class BaseRepository implements Repository { constructor(private model: any) {}

async findById(id: string): Promise<T | null> { return this.model.findById(id); }

async save(entity: T): Promise { return this.model.create(entity); } }

// Использование interface IUser { id: string; email: string; name: string; }

const userRepository = new BaseRepository(UserModel);


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' });
  1. Обобщенные 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(loginSchema), loginController);



**Преимущества в Node.js контексте:**
- Повторное использование кода для разных сущностей
- Автодополнение и проверка типов в IDE
- Безопасность типов при работе с внешними API и базами данных
- Улучшенная читаемость и поддерживаемость кода

Видео-ответы