Почему 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 }