grammY is still pretty young and does not provide any official integrations with DI containers yet. Subscribe to @grammyjs_news to be notified as soon as we support this.
You are free to structure your code however you like, and there is no one-size-fits-all solution. That being said, a straightforward and proven strategy to structure your code is the following.
Group things that semantically belong together in the same file (or, depending on the code size, directory). Every single one of these parts exposes middleware that will handle the designated messages.
Create a bot instance centrally that merges all middleware by installing it onto the bot.
(Optional.) Pre-filter the updates centrally, and send down updates the right way only. You may also want to check out bot.route (API Reference) or alternatively the router plugin for that.
The above structure using composers works well. However, sometimes you may find yourself in the situation that you want to extract a handler into a function, rather than creating a new composer and adding the logic to it. This requires you to add the correct middleware type definitions to your handlers because they can no longer be inferred through the composer.
grammY exports type definitions for all narrowed types of middleware, such as the middleware that you can pass to command handlers. In addition, it exports the type definitions for the narrowed context objects that are being used in that middleware. Both types are parameterized with your custom context object. Hence, a command handler would have the type CommandMiddleware<MyContext> and its context object CommandContext<MyContext>. They can be used as follows.