command icon indicating copy to clipboard operation
command copied to clipboard

strongly-typed args

Open cyberhck opened this issue 7 years ago • 10 comments
trafficstars

EDIT FROM JEFF: despite what this says, we already support strongly-typed flags, but with typescript 3.x I think it would also be possible to support args

As of now, when I try to lookup what values are present on args and flags, it's quite tricky and it's not accurate because of any typing. If we could make it generic something like this:

import {Command, flags} from '@oclif/command'

interface IFlags {
  help: IBooleanFlag
  name: string
  connected: boolean
}
interface IArgs {
  file: string
}

export default class ReactComponent extends Command<IFlags, IArgs> {
  static description = 'Generate react components'

  static flags = {
    help: flags.help({char: 'h'}),
    name: flags.string({char: 'n', description: 'Component Name'}),
    connected: flags.boolean({char: 'c', description: 'add connect()'})
  }
  static args = [{name: 'file'}]
  async run() {
    const {args, flags} = this.parse(ReactComponent)
    const name = flags.name || 'world'
  }
}

I do realize that doing argument parsing is different than it is now, that could be tackled either with next major version with breaking changes, or we can find a way around that (or simply say parse will return that type). This would improve experience by so much.

cyberhck avatar Aug 04 '18 06:08 cyberhck

Flags are already strongly typed. With TypeScript 2 args are not possible, but it might be possible with TypeScript 3. I don't think we need to use genetics though

jdx avatar Aug 04 '18 06:08 jdx

I mean, flags are strongly typed already, but the type inference isn't great, for some reason when I type flags. my IDE doesn't already seem to know what they are, and also it shadows the same var from static

cyberhck avatar Aug 04 '18 07:08 cyberhck

It must be something in your setup because it works in the sample project screen shot 2018-08-06 at 10 27 01 am

jdx avatar Aug 06 '18 17:08 jdx

any progress on this?

scvgoe avatar Aug 12 '19 08:08 scvgoe

Ideally, I'd like to describe args and flags as another class with decorators. For example:

class MyCommandOptions {
  @flag()
  force: boolean;
  @argument({/* additional options here */})
  name: string;
}

Then, when I parse flags and arguments, I'm given an instance of that class, or at least an object matching the interface.

cspotcode avatar Oct 30 '19 14:10 cspotcode

@cspotcode neat idea, adding it to list of possible features

RasPhilCo avatar Nov 07 '19 00:11 RasPhilCo

Decorators were something I considered but that would mean non-TS CLIs would have to use babel which I wasn’t willing to do.

The TC39 proposal is moving slowly and my understanding is it’s also not compatible with TS decorators.

I do like the syntax, but really decorators aren’t a “thing” yet.

jdx avatar Jan 21 '20 21:01 jdx

That's totally fair, but if I may make the case for decorators:

They'll be optional. There will be a non-decorator way to achieve the same effect. This means anyone not using TS or babel can use the non-decorator approach, which is totally fine and will work well. Those on TS and Babel can opt-in to the nicer syntax with less repetition. Again, totally optional.

The decorators are not modifying the class other than building a metadata object; for example, they're not wrapping methods or generating getter/setter pairs. They'll be a minimal layer on top of the non-decorator API. This is using such a limited subset of decorator functionality that differences between the 2 specs should not be an issue. The decorator needs a reference to the class and the name of the field. We can avoid getting into decorator metadata, requiring users to specify the type via arguments to the decorator. (@argument({type: 'string'}) foo: string)

cspotcode avatar Jan 21 '20 21:01 cspotcode

What about declaring args like flags by specifying an object, but add a position prop which will signify the position of the arg?

moltar avatar May 23 '20 14:05 moltar

Powershell is a great example of unifying args and flags. What's cool about that, is you can pass positionally or be more explicit and pass by name. When being explicit you can also change the order. They also let you "splat" an args dictionary into a command, which really only works in Powershell where everything is in-process, but it's still cool to think about.

On Sat, May 23, 2020, 10:25 AM Roman [email protected] wrote:

What about declaring args like flags by specifying an object, but add a position prop which will signify the position of the arg?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/oclif/command/issues/43#issuecomment-633063991, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAC35OAWGTGVMFDRYFP6AIDRS7MFHANCNFSM4FN3OQEA .

cspotcode avatar May 23 '20 20:05 cspotcode