{
"$type": "site.standard.document",
"canonicalUrl": "https://johnnyreilly.com/posts/yargs-statically-typed-builder-commands",
"description": "This post demonstrates how to use Yargs to create statically typed commands with builders in TypeScript.",
"path": "/posts/yargs-statically-typed-builder-commands",
"publishedAt": "2025-11-29T00:00:00.000Z",
"site": "at://did:plc:yy3apqjlms24kso7ahn7lbmb/site.standard.publication/3mova7c4nho2b",
"tags": [
"typescript"
],
"textContent": "Yargs is a popular library for building command line interfaces in Node.js. And the name is just fabulous. Yargs provides a way to define commands, options, and arguments in a structured way. However, Yargs has been around for a long time and it the documentation makes little mention of TypeScript support.\n\nWhilst there is some documentation, if you're building more involved command line interfaces with Yargs in TypeScript, you may find that you need to do a bit of extra work to get strong typing working well with commands that have builders. In this post, I'll demonstrate how to use Yargs to create statically typed commands with builders in TypeScript.\n\nBefore we start, I should say that I'm working with Yargs version 18.0.0 in this post. The type definitions come from Definitely Typed and the version is 17.0.35. However, there is no significant difference in the types between Yargs 17 and 18 and so the difference is not an issue.\n\nAs an aside, it's possibly worth mentioning that these days it's possible to go without third party libraries entirely to parse command line arguments thanks to features like parseArgs which have been part of Node.js since version 18. However, Yargs remains a popular choice and is still widely used. I have no plans to replace Yargs in my existing projects just yet.\n\n\n\nGetting the builders in\n\nLet's start with a simple example. Imagine we want to create a command line tool that has a number of commands. Each command has its own options, and we want to use builders to define those options. Here's how we might set that up with Yargs, first we have a main entry point:\n\nAs we can see, this imports a single command called mySimpleCommand. Let's look at how that command is defined:\n\nYou can see we have a command called simple-command that has a single option called myOption in the builder. However, if we look at the handler function, we can see that myOption is of type unknown. This is because Yargs does not know the shape of the arguments that will be passed to the handler.\n\nThis is the problem we need to solve. Inside the handler, we want to have statically typed access to the options defined in the builder.\n\nStatically typing command builders\n\nTo achieve strong typing, we can define an interface that describes the shape of the arguments for our command. We can then use this interface to type the CommandModule. Here's how we can modify the mySimpleCommand to achieve this:\n\nThere's three things to note here:\n\n1. We've defined an Args interface that describes the shape of the arguments for the command.\n2. We've updated the CommandModule type to use Args as the second type, which defines the return type of the builder.\n3. In the builder, we've specified the type of myOption as string. This is crucial for strong typing to work correctly. Without this we will have compilation errors from TypeScript.\n\nNow we have statically typed access to myOption inside the handler. Yay!\n\nSharing options among commands and builders\n\nIt's not unusual to have options that are shared among multiple commands. Imagine a common option that all commands need to use. How can we share that option definition among multiple commands while maintaining strong typing? We can achieve this by defining a shared interface for the common options and a function that adds those options to a builder. Here's how we can do that:\n\nThen, in our command files, we can import the interface and the function and use them like this:\n\nBy following this pattern, we can create statically typed commands with builders in Yargs while also sharing common options among multiple commands.\n\nIt's a beautiful pattern that sparks joy in my soul. Happy coding!",
"title": "Yargs: statically typed builder commands"
}