Skip to content

Commit ff05faf

Browse files
committed
feat: basic type inference for args (closes #1)
1 parent ba75f83 commit ff05faf

File tree

2 files changed

+30
-12
lines changed

2 files changed

+30
-12
lines changed

src/command.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import type { CommandContext, CommandDef } from "./types";
1+
import type { CommandContext, CommandDef, ArgsDef } from "./types";
22
import { CLIError, resolveValue } from "./_utils";
33
import { parseArgs } from "./args";
44

5-
export function defineCommand(def: CommandDef): CommandDef {
5+
export function defineCommand<T extends ArgsDef = ArgsDef>(
6+
def: CommandDef<T>
7+
): CommandDef<T> {
68
return def;
79
}
810

src/types.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,23 @@ export type PositionalArgDef = Omit<_ArgDef<"positional", string>, "alias">;
1717
export type ArgDef = BooleanArgDef | StringArgDef | PositionalArgDef;
1818
export type ArgsDef = Record<string, ArgDef>;
1919
export type Arg = ArgDef & { name: string; alias: string[] };
20-
export type ParsedArgs = Record<string, string | boolean> & { _: string[] };
20+
21+
export type ParsedArgs<T extends ArgsDef = ArgsDef> = { _: string[] } & Record<
22+
{ [K in keyof T]: T[K] extends { type: "positional" } ? K : never }[keyof T],
23+
string | boolean
24+
> &
25+
Record<
26+
{
27+
[K in keyof T]: T[K] extends { type: "string" } ? K : never;
28+
}[keyof T],
29+
string
30+
> &
31+
Record<
32+
{
33+
[K in keyof T]: T[K] extends { type: "boolean" } ? K : never;
34+
}[keyof T],
35+
boolean
36+
>;
2137

2238
// ----- Command -----
2339

@@ -33,21 +49,21 @@ export interface CommandMeta {
3349

3450
export type SubCommandsDef = Record<string, Resolvable<CommandDef>>;
3551

36-
export type CommandDef = {
52+
export type CommandDef<T extends ArgsDef = ArgsDef> = {
3753
meta?: Resolvable<CommandMeta>;
38-
args?: Resolvable<ArgsDef>;
54+
args?: Resolvable<T>;
3955
subCommands?: Resolvable<SubCommandsDef>;
40-
setup?: (context: CommandContext) => any | Promise<any>;
41-
cleanup?: (context: CommandContext) => any | Promise<any>;
42-
run?: (context: CommandContext) => any | Promise<any>;
56+
setup?: (context: CommandContext<T>) => any | Promise<any>;
57+
cleanup?: (context: CommandContext<T>) => any | Promise<any>;
58+
run?: (context: CommandContext<T>) => any | Promise<any>;
4359
};
4460

45-
export interface CommandContext {
61+
export type CommandContext<T extends ArgsDef = ArgsDef> = {
4662
rawArgs: string[];
47-
args: ParsedArgs;
63+
args: ParsedArgs<T>;
4864
cmd: CommandDef;
49-
subCommand?: CommandDef;
50-
}
65+
subCommand?: CommandDef<T>;
66+
};
5167

5268
// ----- Utils -----
5369

0 commit comments

Comments
 (0)