You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
util: parseArgs instead of string and boolean should handle all primitive data types #44484
I assume when you say support for "numbers" you are thinking of it as as explicit type specified by the author, rather than auto-detection? (Both minimist and yargs have reported issues about automatic detection going wrong, some false positives of IDs, some due to overflow.)
Negative numbers clash with the ability to use a digit as an option, like ls -1. This means some compromises are needed to support negative numbers. There is some prior discussion in a PR that proposed one form of negative number support in pkgjs/parseargs#62
I'm comfortable with parseArgs staying simple and not supporting type conversions. (But I am also very comfortable reaching for a library when I need more!)
Honestly, I don't understand the reasoning behind omitting the number type. It's every bit as commonly used as string and boolean. Without it, instead of just specifying a type, you have to manually convert all the values, which is extremely inconvenient.
I'd really like to hear the official rationale for why the number type was left out.
I'd really like to hear the official rationale for why the number type was left out.
Not official, but I helped implement parseArgs and turn the concept into a library.
Basically, "number type" is not necessary for a basic argument parser. We were focused on solid and safe. The core concepts are options which are used alone (aka type: 'boolean'), options which have an option-argument (aka type: 'string'), and arguments which are not options (allowPositionals: true).
"number type" sounds simple, and it is simple to (say) call parseFloat() and call it done. But what might you care about when you convert a number strictly?
integer vs float
partial non-numbers (e.g. 12foo)
non-numbers (e.g. bar)
numbers larger than can be represented in JavaScript number
floating point representation (e.g. 1e3)
positive only numbers (especially integers, like port number)
Hi @shadowspawn, thanks for the clarification.
If this problem has already been solved in the neighboring ecosystem and in every well-known library, why not use them as a reference?
Here are my examples:
importargparse# 1. Negative number as an OPTION VALUE: -a -42parser=argparse.ArgumentParser()
parser.add_argument('-a', type=int)
args=parser.parse_args(['-a', '-42'])
print(args.a) # -42
importargparse# 2. Negative number as a POSITIONAL argument: -1parser=argparse.ArgumentParser()
parser.add_argument('number', type=int)
args=parser.parse_args(['-1'])
print(args.number) # -1
importargparse# 3. Digit short option TAKES PRECEDENCE: -1 Xparser=argparse.ArgumentParser()
parser.add_argument('-1', dest='one')
parser.add_argument('foo', nargs='?')
args=parser.parse_args(['-1', 'X'])
print(args.one) # X (option -1 consumed X as its value)print(args.foo) # None (no positional left)
importargparse# 4. POSIX '--' terminator: everything after -- is positionalparser=argparse.ArgumentParser()
parser.add_argument('-1', dest='one')
parser.add_argument('foo', nargs='?')
args=parser.parse_args(['--', '-1'])
print(args.foo) # -1 (forced positional)print(args.one) # None (option -1 was not triggered)
importargparse# 5. FLOAT vs INT: the caller CHOOSES the type explicitlyparser=argparse.ArgumentParser()
parser.add_argument('--scale', type=float)
args=parser.parse_args(['--scale', '1e3'])
print(args.scale) # 1000.0
importargparse# 11. STRICT RANGE (0-100)# choices works for discrete integer rangesparser=argparse.ArgumentParser()
parser.add_argument('--percent', type=int, choices=range(0, 101))
args=parser.parse_args(['--percent', '42'])
print(args.percent) # 42
importargparse# 12. CUSTOM TRANSFORM FUNCTIONdefpositive_int(value):
ivalue=int(value)
ifivalue<=0:
raiseargparse.ArgumentTypeError(f"{value} must be positive")
returnivalueparser=argparse.ArgumentParser()
parser.add_argument('--workers', type=positive_int)
args=parser.parse_args(['--workers', '4'])
print(args.workers) # 4
import{parseArgs}from'util';// 1. Negative number as an OPTION VALUE: -a -42constexample1=parseArgs({options: {a: {type: 'number'}},args: ['-a','-42']});console.log(example1.values);// { a: -42 }// 2. Negative number as a POSITIONAL argument: -1constexample2=parseArgs({allowPositionals: true,args: ['-1']});console.log(example2.positionals);// ['-1']// 3. Digit short option TAKES PRECEDENCE: -1 Xconstexample3=parseArgs({options: {1: {type: 'string'}},allowPositionals: true,args: ['-1','X']});console.log(example3.values);// { '1': 'X' }console.log(example3.positionals);// []// 4. POSIX '--' terminator: everything after -- is positionalconstexample4=parseArgs({options: {1: {type: 'string'}},allowPositionals: true,args: ['--','-1']});console.log(example4.positionals);// ['-1']console.log(example4.values);// {}// 5. FLOAT vs INT: the caller CHOOSES the type explicitlyconstexample5=parseArgs({options: {scale: {type: (v)=>parseFloat(v)}},args: ['--scale','1e3']});console.log(example5.values);// { scale: 1000 }// 6. PARTIAL non-numbers ('12foo') — FAILtry{constexample6=parseArgs({options: {id: {type: (v)=>{if(!/^\d+$/.test(v)){thrownewTypeError(`invalid number value: '${v}'`);}returnparseInt(v,10);}}},args: ['--id','12foo']});}catch(err){console.log(err.message);// invalid number value: '12foo'}// 7. Pure non-numbers ('bar') — failuretry{constexample7=parseArgs({options: {id: {type: (v)=>{constn=parseInt(v,10);if(isNaN(n)){thrownewTypeError(`invalid number value: '${v}'`);}returnn;}}},args: ['--id','bar']});}catch(err){console.log(err.message);// invalid number value: 'bar'}// 8. ARBITRARY PRECISION integersconstexample8=parseArgs({options: {big: {type: BigInt}},args: ['--big','999999999999999999999']});console.log(example8.values);// { big: 999999999999999999999n }// 9. HEX / OCT / BIN formats — custom transform via lambdaconstexample9=parseArgs({options: {addr: {type: (v)=>parseInt(v,0)}},args: ['--addr','0xFF']});console.log(example9.values);// { addr: 255 }// 10. POSITIVE-ONLY numbers (e.g., port) — choices constrains the domain// The parser rejects out-of-range values before your code runs.constexample10=parseArgs({options: {port: {type: 'number',choices: Array.from({length: 65535},(_,i)=>i+1)}},args: ['--port','8080']});console.log(example10.values);// { port: 8080 }// 11. STRICT RANGE (0-100)constexample11=parseArgs({options: {percent: {type: 'number',choices: Array.from({length: 101},(_,i)=>i)}},args: ['--percent','42']});console.log(example11.values);// { percent: 42 }// 12. CUSTOM TRANSFORM FUNCTIONfunctionpositiveInt(value){constn=parseInt(value,10);if(isNaN(n)||n<=0){thrownewTypeError(`${value} must be positive`);}returnn;}constexample12=parseArgs({options: {workers: {type: positiveInt}},args: ['--workers','4']});console.log(example12.values);// { workers: 4 }
I may have missed something, but as of today util.parseArgs doesn't even expose choices or transform / custom type functions to work around the missing number type. Without those, users are left with zero built-in tools and forced to do raw string post-processing on every single call site.
Activity
shadowspawn commentedon Sep 3, 2022
Just regarding numbers.
I assume when you say support for "numbers" you are thinking of it as as explicit type specified by the author, rather than auto-detection? (Both minimist and yargs have reported issues about automatic detection going wrong, some false positives of IDs, some due to overflow.)
Negative numbers clash with the ability to use a digit as an option, like
ls -1. This means some compromises are needed to support negative numbers. There is some prior discussion in a PR that proposed one form of negative number support in pkgjs/parseargs#62I'm comfortable with
parseArgsstaying simple and not supporting type conversions. (But I am also very comfortable reaching for a library when I need more!)mcollina commentedon Sep 4, 2022
I don't think we should support streams or any other complex types. That's best left to userland.
Mouvedia commentedon Oct 3, 2024
type: "number"would have been a welcomed addition.meowsupports it.monolithed commentedon Aug 28, 2026
Honestly, I don't understand the reasoning behind omitting the
numbertype. It's every bit as commonly used as string and boolean. Without it, instead of just specifying a type, you have to manually convert all the values, which is extremely inconvenient.I'd really like to hear the official rationale for why the number type was left out.
shadowspawn commentedon Aug 28, 2026
Not official, but I helped implement
parseArgsand turn the concept into a library.Basically, "number type" is not necessary for a basic argument parser. We were focused on solid and safe. The core concepts are options which are used alone (aka
type: 'boolean'), options which have an option-argument (akatype: 'string'), and arguments which are not options (allowPositionals: true)."number type" sounds simple, and it is simple to (say) call
parseFloat()and call it done. But what might you care about when you convert a number strictly?12foo)bar)numbermonolithed commentedon Aug 28, 2026
Hi @shadowspawn, thanks for the clarification.
If this problem has already been solved in the neighboring ecosystem and in every well-known library, why not use them as a reference?
Here are my examples:
I may have missed something, but as of today
util.parseArgsdoesn't even exposechoicesortransform/ customtypefunctions to work around the missing number type. Without those, users are left with zero built-in tools and forced to do raw string post-processing on every single call site.ljharb commentedon Aug 29, 2026
https://npmjs.com/pargs is my parseArgs wrapper that adds enum, number, and integer types, along with some other handy things, if that's helpful.