v4.0
Changelog Telegraf 4.0
General
- Port to TypeScript
- Update to Bot API 5.0
- Scenes now live in their own namespace called
Scenes
- Allow cancelling requests via
AbortController
- Add
attachmentAgent
option to provide an agent that is used for fetching files from the web before they are sent to Telegram (previously done through the sameagent
as used to connect to Telegram itself)
Apart from updating Telegraf to full Telegram Bot API 5.0 support, the most significant improvement is that we now have a code base that is written 100 % in TypeScript, which more or less required a rewrite of the complete library.
Previously, the library was written in JavaScript and had a few type annotations to the side, but they were often incorrect or missing.
In working on the 4.0 release, we created type coverage of the complete Telegram Bot API.
The benefit is that your editor can now autocomplete accross every single field in every single method or entity.
Those who ever tried it out can confirm that this improves the development experience by an order of magnitude.
Note that this update brings 9 months worth of improvements, so while we did our best to summarise all important changes, it's possible that we forgot some!
Composer
- Add
Composer.guard
- Deprecate
static Composer.mount
, preferstatic Composer.on
- Make
Composer.entity
andComposer.match
private - Remove
Composer.catchAll
andComposer.safePassThru
- Catch errors of both branches of
Composer.fork
- Listen to forwards using
on('forward_date')
, no longeron('forward')
Context
- Make
ctx.botInfo
required, i.e. is is always available - Make
ctx.state
readonly
- Add
ctx.senderChat
,ctx.unpinAllChatMessages
, andctx.copyMessage
ctx.deleteMessage
no longer works for edited messages, channel posts, or edited channel posts- Remove
ctx.updateSubTypes
Extra
Extra
is removed entirely, see #1076.
You can now just specify any options directly, without having to create an Extra
instance before.
Markup
Markup
is largely reworked.
Please check out the new documentation about Markup
, this is much easier than trying to understand the differences between the old and the new version.
The TypeScript autocompletion should help you a lot in case you have to change something about your code.
The main thing to watch out for is that all buttons (keyboard buttons and inline buttons) are now created via Markup.button.url
and its siblings, no longer via Markup.urlButton
.
The integration with Extra
is removed.
Session
Remove the ability to specify a custom property on the context object under which the session lives, in other words, the session data can only be available under ctx.session
.
Note that this also applies to scene sessions, they now exclusively live under ctx.scene.session
.
When no session data is stored, ctx.session
is now undefined
instead of {}
.
Telegraf
Bots should now always be started using bot.launch
with the corresponding configuration for either long polling (default) or webhooks.
startPolling
andstartWebhook
are now privateTimeoutError
is now thrown if update takes longer thanhandlerTimeout
to processhandlerTimeout
defaults to 90 secondsstop
returnsvoid
and takesreason
instead of callback as as an argumentchannelMode
is removed
Polling
- Remove
retryAfter
option (used in an error case), always using 5 seconds now - Remove
timeout
option, always using 50 seconds now - Remove
limit
option, always fetching 100 updates now - Remove
stopCallback
option
Common typing issues
Naturally, if your editor validates your code against the TypeScript types, you may find a few bugs here and there that you were not aware of.
Here are a few things you might come across and that we'd like to explain.
Property X is not available
for messages, callback queries, etc
This happens in various different forms, one example is this:
bot.on("message", (ctx) => {
const text = ctx.message.text;
// ^ error here!
// Property 'text' does not exist on type ...
});
We are listening for message
s here, but not all messages are text messages!
As a result, the text property might be absent, for example for photo messages.
Here is how you solve it:
bot.on("message", (ctx) => {
if ("text" in message) {
// now we know that we have a text message!
const text = ctx.message.text; // works!
console.log(text);
}
});
Remember that you can always just do this instead:
bot.on("text", (ctx) => {
// we already know that we have a text message!
const text = ctx.message.text; // works!
console.log(text);
});
Cannot access ctx.session
or ctx.scene
or ctx.wizard
type
If you are using sessions, scenes, wizards, or even yet another of the many modules that work with Telegraf, you have to define your own context object.
This context object must specify which types your middleware registers on the context.
We cannot infer this automatically.
This is best explained by an example bot.
Here is one that's relevant: https://github.com/telegraf/telegraf/blob/develop/docs/examples/example-bot.ts
Scenes have various examples here: https://github.com/telegraf/telegraf/tree/develop/docs/examples/scenes
I see a really complicated type error message!
Middleware in Telegraf is very flexible, so we have to do some really fancy stuff under the hood when we infer the types for you.
Whenever you type bot.on(['callback_query', 'text'], (ctx) => ctx.|
, and autocomplete shows up, we have to look at the first argument of bot.on
, iterate through the array, look at each string in it, and then do a type transformation on the complete Bot API surface to filter out which options are even available on the relevant context objects at this point.
All of this computation happens on the type level.
(Fun fact: in the first iteration of this feature it took up to 20 seconds for autocomplete to show up.)
The point is: types are hard.
It was our main priority to make the types correct, and then we focused on making the type inference fast.
We would love to make TypeScript print more readable type errors, and we are actively looking trying a few things to do this without too much black magic.
Until then, don't give up!
Here's what you can do:
- Remember that most type errors come from typos in variable names or other tiny mistakes.
Double check this first, the problem may be simpler than you thought. - Even complex error messages have parts in them that you understand!
Look out for these parts, they often help to fix the problem. - The community can help you.
Don't hesitate to share a code snippet in the Telegram group.
You are probably not the only one with this problem.