TypeScript and Keyboard Types
What we'll do
- Learn to run TypeScript files using TSX
- Type our
process.env
- Get to know keyboards and their types
- Learn to respond to regular messages and inline keyboard button clicks
Running TypeScript Files in Node.js
Don't be afraid. We're not going to use any special TypeScript features except for type hints right now.
At the time of writing this guide, native support for running TypeScript files is just appearing in Node.js, but it's too early to use it now. So we'll use the excellent "TSX" library.
First, we need to change the extension of our index.js
file from JavaScript to TypeScript (i.e., rename it to index.ts
). Then we can try tsx
with a simple command:
npx tsx watch --env-file=.env index.ts
Pretty simple! Now let's replace the contents of the dev
command in our package.json
file with this command.
Typing process.env
Unfortunately, TypeScript doesn't know what's in our .env
file, so it can't provide hints. After renaming the file, you should have gotten an error when using the BOT_TOKEN
environment variable, so let's fix this by adding to the end of the file:
declare global {
namespace NodeJS {
interface ProcessEnv {
BOT_TOKEN: string;
}
}
}
Don't worry, what we did is called "declaration merging" - we merged the TypeScript interface type for process.env
with the values we need in the global scope. For now, you can just accept it as is! The important thing is that the error has disappeared and hints are now available!
process.env.B;
Getting to Know Keyboards and Their Types
Keyboard
Let's write a handler for the /start
command and send a regular keyboard to the user:
import { Bot, Keyboard } from "gramio";
const bot = new Bot(process.env.BOT_TOKEN)
.command("start", (context) =>
context.send("You sent /start", {
reply_markup: new Keyboard().text("Ping"),
})
)
.hears("Ping", (context) => context.send("Pong"));
bot.start();
Let's understand what new Keyboard().text("Ping")
is:
new Keyboard().text("Ping");
This construct written with the convenient Keyboard
class hides behind it some complex things and is actually sent to Telegram like this:
{
"keyboard": [
[
{
"text": "Ping"
}
]
],
"one_time_keyboard": false,
"is_persistent": false,
"selective": false,
"resize_keyboard": true
}
The hears
method, unlike command
, listens to all messages and checks if they match the specified text.
InlineKeyboard
Now let's explore the power of InlineKeyboard
! Let's send an inline keyboard to the user along with "Pong":
import { Bot, Keyboard, InlineKeyboard } from "gramio";
const bot = new Bot(process.env.BOT_TOKEN)
.command("start", (context) =>
context.send("You sent /start", {
reply_markup: new Keyboard().text("Ping"),
})
)
.hears("Ping", (context) =>
context.send("Pong", {
reply_markup: new InlineKeyboard().text("Ping", "ping"),
})
);
bot.start();
You might wonder what the 2nd argument in the text
function is - it's the payload
. Essentially, it's a string that Telegram will return to us when notifying about a clicked button. Let's handle this event. It's called callback_query
and GramIO has a convenient shorthand for it:
import { Bot, Keyboard, InlineKeyboard } from "gramio";
const bot = new Bot(process.env.BOT_TOKEN)
.command("start", (context) =>
context.send("You sent /start", {
reply_markup: new Keyboard().text("Ping"),
})
)
.hears("Ping", (context) =>
context.send("Pong", {
reply_markup: new InlineKeyboard().text("Ping", "ping"),
})
)
.callbackQuery("ping", async (context) => {
await context.answer("Pong to your forehead");
return context.editText("Pong, but from a callback_query!");
});
bot.start();