如何在Yargs命令处理器中定义/获取argv的类型?
解决Yargs CLI中handler的argv类型为unknown的问题
核心原因
Yargs 默认无法自动从 builder 配置中推断出参数类型,即便安装了 @types/yargs,也需要手动为每个命令的参数定义类型,或者通过泛型指定类型。
解决方案步骤
1. 导入Yargs类型工具
首先导入 ArgumentsCamelCase 类型,它会自动处理参数的驼峰转换(比如将--foo-bar转为fooBar):
import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; import type { ArgumentsCamelCase } from 'yargs'; // 导入类型工具
2. 为每个命令定义参数类型
针对不同命令的参数结构,定义对应的类型:
// register命令的参数类型 type RegisterCommandArgs = ArgumentsCamelCase<{ global: boolean; // 对应builder里的global选项 }>; // delete命令的参数类型 type DeleteCommandArgs = ArgumentsCamelCase<{ id: string; // 必选的id参数 global: boolean; // 可选的global选项 }>;
3. 在handler中绑定类型
有两种方式可以让TS识别argv的类型:
方式一:直接在handler参数中指定类型
.command({ command: 'register [options]', describe: 'register', builder: { global: { alias: 'g', type: 'boolean', description: 'register globally', default: false, }, }, handler: async (argv: RegisterCommandArgs) => { const { global } = argv; // global类型自动识别为boolean // 业务逻辑代码 }, })
方式二:通过command泛型指定类型
.command<DeleteCommandArgs>( 'delete <id> [options]', 'delete command with id', (yargs) => { yargs.option('id', { describe: 'The id', type: 'string', }); yargs.option('global', { alias: 'g', type: 'boolean', description: 'delete globally', default: false, }); }, (argv) => { const { id, global } = argv; // id为string,global为boolean // 业务逻辑代码 } )
4. 优化不必要的异步调用
注意parseSync()是同步方法,不需要用await,可以简化代码结构:
// 去掉不必要的await,直接执行同步解析 yargs(hideBin(process.argv)) .scriptName('') .alias('v', 'version') .alias('h', 'help') // ... 其他配置和命令 .strict() .parseSync();
完整修改后的代码示例
#!/usr/bin/env node import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; import type { ArgumentsCamelCase } from 'yargs'; // 定义命令参数类型 type RegisterCommandArgs = ArgumentsCamelCase<{ global: boolean; }>; type DeleteCommandArgs = ArgumentsCamelCase<{ id: string; global: boolean; }>; yargs(hideBin(process.argv)) .scriptName('') .alias('v', 'version') .alias('h', 'help') .option('global', { alias: 'g', describe: 'perform globally', type: 'boolean', }) .command({ command: 'register [options]', describe: 'register', builder: { global: { alias: 'g', type: 'boolean', description: 'register globally', default: false, }, }, handler: async (argv: RegisterCommandArgs) => { const { global } = argv; console.log('register global:', global); }, }) .command<DeleteCommandArgs>( 'delete <id> [options]', 'delete command with id', (yargs) => { yargs.option('id', { describe: 'The id', type: 'string', }); yargs.option('global', { alias: 'g', type: 'boolean', description: 'delete globally', default: false, }); }, (argv) => { const { id, global } = argv; console.log('delete id:', id, 'global:', global); } ) .strict() .parseSync();
内容的提问来源于stack exchange,提问作者ChrisGM
相关产品推荐
相关产品推荐

