Allow readonly array as parameter of .choices()#1667
Allow readonly array as parameter of .choices()#1667shadowspawn merged 5 commits intotj:release/9.xfrom ouuan:choices-allow-readonly-array
Conversation
Without `readonly`, readonly arrays cannot be passed as parameters. Example: https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABMAjACgIYCcsC5EDOUWMYA5gNoC6AlIgN4C+AUKJLAsgEyY75YBTDABMEAGwCehYqUq0GLZhARFE2LCkQBeRBQDkGPVQDcSlVDU4u23QaNqCiZWCKnW6dShqngPT9-deLC4A3yCQ4yA
|
I have been doing a bit of reading and still thinking about this. Just changing the type does allow passing a ReadonlyArray as parameter, and reflects the intent that the call itself will not change the array, and lets the caller prevent casual changes to their reference to the array. However, the Commander code effectively removes the readonly in the implementation, so it is weak! The array is stored in choices(values) {
this.argChoices = values;
...
}The readonly could be honoured by taking a defensive copy of the parameter: choices(values) {
this.argChoices = Array.isArray(values) ? values.slice() : values;
...
}Reference: Related:
|
|
I don't think readonly can be used for parameters in JSDoc? |
Could you elaborate on why |
Hmm, good question. Probably not needed! I was being paranoid, and had in mind perhaps passing |
|
For interest, what is your use case? (Why do you have a readonly array of choices?) |
I use a library that provides a union type for valid options. The library doesn't provide an array for the valid options, so I created a readonly array in my own code that contains these options and type-checked the array against the union type provided by the library. |
lib/argument.js
Outdated
| this.argChoices = values; | ||
| this.argChoices = values.slice(); | ||
| this.parseArg = (arg, previous) => { | ||
| if (!values.includes(arg)) { |
There was a problem hiding this comment.
The uses of values in the parse function should be replaced with this.argChoices now they may be different.
lib/option.js
Outdated
| this.argChoices = values; | ||
| this.argChoices = values.slice(); | ||
| this.parseArg = (arg, previous) => { | ||
| if (!values.includes(arg)) { |
There was a problem hiding this comment.
The uses of values in the parse function should be replaced with this.argChoices now they may be different.
|
I offered some tests in a PR back to the branch to check the parameter is actually treated as readonly at runtime. |
shadowspawn
left a comment
There was a problem hiding this comment.
I don't think this will be widely needed and requires taking a defensive copy of param, but do I like making the TypeScript API more usable (readonly) and safer (defensive copy).
Thumbs up from me. 👍
|
Commander v9 has been released. |
Problem
Without
readonly, readonly arrays cannot be passed as parameters.Example: https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABMAjACgIYCcsC5EDOUWMYA5gNoC6AlIgN4C+AUKJLAsgEyY75YBTDABMEAGwCehYqUq0GLZhARFE2LCkQBeRBQDkGPVQDcSlVDU4u23QaNqCiZWCKnW6dShqngPT9-deLC4A3yCQ4yA
Solution
Add
readonlyin the TypeScript typings.ChangeLog
Allow readonly arrays as parameters of
.choices().