Describe the feature
Today an argument can hold at most one value. There is no supported way to accept a flag repeatedly,
such as --environment A=1 --environment B=2, or to accept several positionals of the same kind,
such as lint fileA.ts fileB.ts. The only workaround is to reach into ctx.args._ and parse them by
hand, which loses typing, validation, and help output.
This has come up several times before:
Each prior proposal solved a slice of the problem, usually positionals only, and modeled
multiplicity as a new type, which does not compose with the existing string, enum, and
positional types or with required.
Proposal
I propose we add an optional multiple?: boolean modifier that any argument can set. It is
orthogonal to type and to the existing required field, and it defaults to false, so nothing
changes for current definitions.
Together, multiple and required form a 2×2 matrix that expresses the full range of cardinality.
These correspond to the same four cases regular expressions express with ?, *, +, and a bare
match:
required |
multiple |
cardinality |
regex analog |
parsed type |
false (default) |
false (default) |
zero or one |
? |
T | undefined |
true |
false |
exactly one |
(bare) |
T |
false |
true |
zero or more |
* |
T[] |
true |
true |
one or more |
+ |
T[] |
Because both fields already default to false, this is purely additive. Existing commands keep the
exact behavior they have now, and required keeps working as before, since it simply becomes the
multiple: false row of the matrix.
One constraint applies to positionals: only the last positional may be multiple, since a variadic
positional consumes the remaining tokens. At most one positional can set it, and declaring a
multiple positional before another positional should be a definition-time error.
Examples
A repeatable flag (zero or more):
export default defineCommand({
args: {
environment: {
type: "string",
alias: "e",
multiple: true,
description: "Environment variable as NAME=VALUE (repeatable)",
},
},
run({ args }) {
// mycommand -e A=1 -e B=2
args.environment; // => ["A=1", "B=2"], typed as string[]
},
});
A variadic positional (one or more):
export default defineCommand({
args: {
files: {
type: "positional",
required: true,
multiple: true,
description: "Files to lint",
},
},
run({ args }) {
// lint fileA.ts fileB.ts
args.files; // => ["fileA.ts", "fileB.ts"], typed as string[]
},
});
Describe the feature
Today an argument can hold at most one value. There is no supported way to accept a flag repeatedly,
such as
--environment A=1 --environment B=2, or to accept several positionals of the same kind,such as
lint fileA.ts fileB.ts. The only workaround is to reach intoctx.args._and parse them byhand, which loses typing, validation, and help output.
This has come up several times before:
type: "multiple".multipleinArgType: closed as a duplicate of the above, with the sametype: "multiple"idea.multiPositionaltype.Each prior proposal solved a slice of the problem, usually positionals only, and modeled
multiplicity as a new type, which does not compose with the existing
string,enum, andpositionaltypes or withrequired.Proposal
I propose we add an optional
multiple?: booleanmodifier that any argument can set. It isorthogonal to
typeand to the existingrequiredfield, and it defaults tofalse, so nothingchanges for current definitions.
Together,
multipleandrequiredform a 2×2 matrix that expresses the full range of cardinality.These correspond to the same four cases regular expressions express with
?,*,+, and a barematch:
requiredmultiplefalse(default)false(default)?T | undefinedtruefalseTfalsetrue*T[]truetrue+T[]Because both fields already default to
false, this is purely additive. Existing commands keep theexact behavior they have now, and
requiredkeeps working as before, since it simply becomes themultiple: falserow of the matrix.One constraint applies to positionals: only the last positional may be
multiple, since a variadicpositional consumes the remaining tokens. At most one positional can set it, and declaring a
multiplepositional before another positional should be a definition-time error.Examples
A repeatable flag (zero or more):
A variadic positional (one or more):