Skip to content

Почему GramIO

GramIO — это TypeScript-first фреймворк для Telegram Bot API, работающий на Node.js, Bun и Deno. Он построен вокруг одной идеи: система типов должна работать на вас, а не против вас.

Вот что это значит на практике.


Типы, которые текут, а не с которыми борешься

Большинство фреймворков дают вам типизированный контекст на входе. GramIO идёт дальше — типы распространяются по всей цепочке по мере её построения.

ts
import { Bot } from "gramio";
import { db } from "./db";

const bot = new Bot(process.env.BOT_TOKEN as string)
    // добавляем в каждый обработчик — типизируется автоматически
    .derive(async (ctx) => ({
        user: await db.getUser(ctx.from!.id),
    }))
    // ctx.user полностью типизирован здесь
    .on("message", (ctx) => {
        ctx.user.role;
        //
        //
        return ctx.send(`Привет, ${ctx.user.name}!`);
    })
    // ...и здесь, для другого события
    .on("callback_query", (ctx) => ctx.user.balance);

Никакого приведения типов. Никаких ручных аннотаций. Никакого (ctx as any).user.


Форматирование без parse_mode

Форматирование Telegram через HTML или MarkdownV2 — это боль: нужно экранировать всё вручную и следить за parse_mode. GramIO использует тегированные шаблонные строки, которые создают корректные объекты MessageEntity:

ts
bot
.
command
("start", (
ctx
) =>
ctx
.
send
(
format
`${
bold
`Добро пожаловать!`} — ${
italic
("parse_mode не нужен")}.
Версия: ${
code
("2.0.0")}
${
spoiler
`секрет`} · ${
link
("gramio.dev", "https://gramio.dev")}`
) );

Никакого экранирования. Никакого parse_mode: "HTML". Никаких сломанных сообщений из-за < или > в тексте.


Плагины, которые компонуются, а не конфигурируются

Плагины в GramIO используют .extend() — тот же механизм, что и всё остальное. Плагин может добавлять свойства контекста, регистрировать обработчики и встраиваться в жизненный цикл. И всё это с полной типизацией:

ts
import { Bot } from "gramio";
import { scenes, Scene } from "@gramio/scenes";
import { session } from "@gramio/session";

const onboarding = new Scene("onboarding")
    .step("message", (ctx) => {
        if (ctx.scene.step.firstTime) return ctx.send("Как вас зовут?");
        return ctx.scene.update({ name: ctx.text });
    })
    .step("message", (ctx) =>
        ctx.send(`Добро пожаловать, ${ctx.scene.state.name}!`)
    );

const bot = new Bot(process.env.BOT_TOKEN as string)
    .extend(session())
    .extend(scenes([onboarding]))
    .command("start", (ctx) => ctx.scene.enter(onboarding));
//                              полная типизация — ctx.scene из плагина

bot.start();

Сравнение

ВозможностьGramIOgrammYTelegraf
ЯзыкTypeScriptTypeScriptTypeScript
Распространение типов через middleware✅ Полное✅ Полное⚠️ Частичное
derive() с авто-типизацией контекста
Форматирование без parse_mode✅ Встроено❌ Вручную❌ Вручную
Система плагинов.extend()✅ Flavors⚠️ Middleware
Мультирантайм (Node/Bun/Deno)⚠️ Node в приоритете
Автогенерируемые типы API✅ Авто-публикация⚠️
Встроенные утилиты для тестирования@gramio/test
Полный референс Telegram API/telegram/
Сцены / диалоги@gramio/scenes✅ Conversations✅ Scenes
I18n@gramio/i18n (Fluent)⚠️
CLI для скаффолдингаcreate gramio

Всё — это Composer

Bot расширяет Composer — цепочный типобезопасный конвейер обработки middleware. Каждый .derive(), .guard(), .on() возвращает обновлённый тип. Можно выделить Composer для любой фичи, тестировать его изолированно, а затем .extend() его в бот:

ts
// src/plugins/index.ts — регистрация один раз
export const composer = new Composer()
    .extend(session())
    .extend(scenes([onboarding]));

// src/features/profile.ts — полная типизация, Bot не нужен
export const profileFeature = new Composer()
    .extend(composer)          // наследует ctx.session, ctx.scene
    .command("profile", (ctx) => ctx.send(ctx.session.name ?? "anon"));

// src/index.ts — склеиваем всё
const bot = new Bot(token)
    .extend(composer)
    .extend(profileFeature);

Готовы создавать?