Прокачай портфолио: 5 проектов на TypeScript, которые впечатлят работодателя

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему TypeScript — ваш главный козырь в портфолио?

Мир JavaScript — это дикий запад. Динамическая типизация дарит свободу, но часто превращает код в рулетку. TypeScript приходит как шериф, который наводит порядок. Если вы хотите не просто писать код, а строить надёжные, масштабируемые системы — проекты на TypeScript в вашем портфолио скажут за вас всё.

Представьте: вы приходите на собеседование. У всех ребят стандартные TODO-листы на React. А у вас — fully-typed Telegram-бот с авторизацией, real-time чат или свой маленький компилятор. Согласитесь, звучит весомее. В этой статье мы разберём 5 идей для портфолио на TypeScript, которые не только прокачают ваши скиллы, но и заставят рекрутеров залипнуть на вашем GitHub.

Критерии выбора: что делает проект «топовым»?

Прежде чем нырять в код, давайте договоримся. Хороший pet-проект на TypeScript должен:

  • Решать реальную проблему (или хотя бы имитировать это).
  • Использовать продвинутые фичи TS: дженерики, декораторы, utility types.
  • Иметь тесты — покрытие кода показывает вашу ответственность.
  • Быть задокументированным — README с примерами установки и использования.

Готовы? Поехали!

1. Telegram-бот для управления финансами с полной типизацией

Боты — это классика. Но сделать бота на TypeScript с нормальной архитектурой — уже вызов. Мы не просто повесим обработчик на "Привет", а построим микросервис с DI-контейнерами и строгими моделями.

Что внутри?

  • База данных (SQLite или PostgreSQL) с TypeORM.
  • Команды: /add_expense, /stats, /budget.
  • Категории расходов через enum.

Пример кода: типизированная модель и команда

// models/Expense.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm';
import { Category } from './enums';

@Entity()
export class Expense {
    @PrimaryGeneratedColumn()
    id!: number;

    @Column()
    userId!: number;

    @Column('decimal', { precision: 10, scale: 2 })
    amount!: number;

    @Column({
        type: 'enum',
        enum: Category,
        default: Category.OTHER
    })
    category!: Category;

    @CreateDateColumn()
    createdAt!: Date;
}

// commands/addExpense.ts
import { Context } from 'telegraf';
import { getRepository } from 'typeorm';
import { Expense } from '../models/Expense';
import { Category } from '../models/enums';

export async function addExpense(ctx: Context, amount: number, category: Category) {
    const repo = getRepository(Expense);
    const expense = repo.create({
        userId: ctx.from!.id,
        amount,
        category
    });
    await repo.save(expense);
    await ctx.reply(`✅ Добавлено: ${amount} руб. в категорию ${category}`);
}

Почему это круто? Вы показываете умение работать с БД через ORM, понимание асинхронности и строгую типизацию данных. Плюс — реальный сценарий использования.

2. Real-time доска задач (Kanban) на WebSocket + React

Сделать TODO-лист — скучно. Сделать мультипользовательский Kanban с drag-and-drop и WebSocket на TypeScript — уже интересно. Здесь вы раскрываете себя как fullstack-разработчика.

Архитектура

  • Backend: Express + Socket.io + TypeScript.
  • Frontend: React + react-beautiful-dnd + Redux Toolkit.
  • Типизация всех событий (socket events как union types).

Пример: типизированный WebSocket handler

// types/socket-events.ts
export interface ServerToClientEvents {
    taskMoved: (task: Task, fromColumn: ColumnId, toColumn: ColumnId) => void;
    newTask: (task: Task) => void;
}

export interface ClientToServerEvents {
    moveTask: (payload: { taskId: string; toColumn: ColumnId }) => void;
    createTask: (payload: { title: string; columnId: ColumnId }) => void;
}

// server.ts
import { Server } from 'socket.io';

const io = new Server<ClientToServerEvents, ServerToClientEvents>(3000);

io.on('connection', (socket) => {
    socket.on('moveTask', (payload) => {
        // Логика перемещения
        io.emit('taskMoved', movedTask, 'todo', 'in_progress');
    });
});

Полезно: Вы учитесь типизировать не только данные, но и события. Это высший пилотаж для проектов на TypeScript в портфолио.

3. Свой мини-фреймворк для валидации форм

Все используют Zod или Yup. А вы попробуйте написать свою библиотеку! Это идеальный способ показать, как вы работаете с дженериками и рекурсивными типами.

Идея

Создайте утилиту, которая на основе объекта правил генерирует тип результата и проверяет данные.

Пример кода: Generic Validator

// validator.ts
type ValidationRule<T> = {
    [K in keyof T]: (value: T[K]) => boolean;
};

type ValidationResult<T> = {
    [K in keyof T]: { valid: boolean; error?: string };
};

function createValidator<T extends object>(rules: ValidationRule<T>) {
    return (data: T): ValidationResult<T> => {
        const result = {} as ValidationResult<T>;
        for (const key in rules) {
            const isValid = rules[key](data[key]);
            result[key] = {
                valid: isValid,
                error: isValid ? undefined : `Field ${key} is invalid`
            };
        }
        return result;
    };
}

// Использование
interface UserForm {
    email: string;
    age: number;
}

const userValidator = createValidator<UserForm>({
    email: (v) => typeof v === 'string' && v.includes('@'),
    age: (v) => typeof v === 'number' && v > 0
});

const result = userValidator({ email: 'test', age: -5 });
console.log(result.email.valid); // false

Фишка: Вы не просто используете инструменты, а создаёте их. Работодатели это обожают. Добавьте тесты — и готово портфолио разработчика TypeScript.

4. Парсер конфигурационных файлов (YAML/TOML) с AST

Эта идея покажет, что вы шарите за Computer Science. Напишите простой парсер, который превращает строку в AST (Abstract Syntax Tree) и обратно. TypeScript идеально подходит для работы с деревьями.

Пример: AST для YAML-like строки

// types.ts
type Node = 
    | { type: 'string'; value: string }
    | { type: 'number'; value: number }                

Блоги

Рекомендаций по книгам