TypeScript嵌套泛型Command类型:如何实现子命令context正确推断?
解决TypeScript自嵌套泛型命令的类型推断问题
你的问题出在CommandSubs的定义上——它强制所有子命令的参数类型为固定的CommandArgs,而非每个子命令自己的具体参数结构,导致TypeScript无法推断子命令main函数的context类型。以下是修复方案:
问题根源
原代码中CommandSubs = Record<string, Command<CommandArgs, CommandSubs>>的定义,把所有子命令的Args泛型固定成了CommandArgs(即任意string到CommandArg的映射),丢失了每个子命令args的具体结构信息,所以子命令的main函数只能推断出context是宽泛的CommandArgs,而非你定义的{newTest: CommandArg}。
修复后的代码
export interface CommandArg { type?: 'boolean' | 'number' | 'positional' | 'string' alias?: string } export type CommandArgs = Record<string, CommandArg> // 移除原固定泛型的CommandSubs,改为让子命令的类型自动推断 export interface Command<Args extends CommandArgs = CommandArgs, Subs extends Record<string, Command> = Record<string, Command>> { args?: Args subs?: Subs main?: (context: Args) => unknown } export function defineCommand<Args extends CommandArgs, Subs extends Record<string, Command>>(command: Command<Args, Subs>) { return command } const cmd = defineCommand({ args: { test: { type: 'boolean', alias: 'haha' } }, subs: { haha: { args: { newTest: { type: 'boolean', alias: 'haha' } }, main: (context) => { console.error(context.okok) // 此处会报错:类型“{ newTest: CommandArg; }”上不存在属性“okok” console.error(context.newTest.type) // 正常推断,无报错 } } }, main: (context) => { console.error(context.test.type) // 正常推断,无报错 } })
关键修改点
- 移除固定泛型的
CommandSubs:原类型限制了子命令的参数类型,改为让Command的Subs泛型接受任意Record<string, Command>,保留每个子命令的具体类型信息。 - 简化
Command接口的subs定义:去掉原代码中多余的类型映射(Subs & { [K in keyof Subs]: ... }),因为Subs本身已经是Command类型的集合,无需额外约束。 - 调整泛型默认值:给
Command的泛型参数加上默认值,避免使用时手动指定。
进一步优化(支持深度嵌套子命令)
如果需要支持多层嵌套的子命令,TypeScript的递归泛型可以自动处理,上述代码已经具备这个能力。例如添加更深层级的子命令,其main函数的context依然能正确推断:
const cmd = defineCommand({ args: { test: { type: 'boolean' } }, subs: { haha: { args: { newTest: { type: 'boolean' } }, subs: { deeper: { args: { deepArg: { type: 'string' } }, main: (context) => { console.error(context.deepArg.type) // 正确推断 } } }, main: (context) => console.error(context.newTest) } } })
内容的提问来源于stack exchange,提问作者13OnTheCode
相关产品推荐
相关产品推荐

