Conversation
mshanemc
left a comment
There was a problem hiding this comment.
approved but would love to have some assertion about it
| * } | ||
| * } | ||
| */ | ||
| export type InferredFlags<T> = T extends FlagInput<infer F> ? F & { json: boolean | undefined; } : unknown |
There was a problem hiding this comment.
is there any way to test this? Maybe by building a test class and having a flags property like your example, and then asserting things about its type?
What I'd like to do is prevent some future flag changes/refactoring/type fixing from breaking this feature.
mshanemc
left a comment
There was a problem hiding this comment.
lgtm. Will approve once the sf-plugins-core stuff is updated.
Do you want to do the updates on sf-plugins-core or me?
| public flags!: MyFlags | ||
|
|
||
| public async run(): Promise<MyFlags> { | ||
| const result = await this.parse(MyCommand) |
There was a problem hiding this comment.
I understand why the ! is there in here and in your example. It's kinda true...as long as people make
const {flags} = await this.parse(MyCommand) (or whatever) their very first step in run.
Is that worth adding to our linter? Are there situations where someone wouldn't want to parse the flags first (ex: checking some env, etc?) or not at all?
Otherwise, if they do the public flags!: MyFlags but forget to parse (or try to use this.flags before parsing) the compiler won't warn them.
Or maybe the rule is "don't refer to the instance flags prop if you haven't called the parse and assigned it?" ?
| expectType<MyFlags>(this.flags) | ||
|
|
||
| expectType<string>(this.flags.requiredGlobalFlag) | ||
| expectNotType<undefined>(this.flags.requiredGlobalFlag) |
| "lib": ["es2020"], | ||
| "allowSyntheticDefaultImports": true | ||
| "allowSyntheticDefaultImports": true, | ||
| "noErrorTruncation": true, |
There was a problem hiding this comment.
oh, nice. How would you feel about this being in dev-config?
| export type CustomOptionFlag<T, P = any> = FlagBase<T, string, P> & OptionFlagProps & { | ||
| defaultHelp?: DefaultHelp<T>; | ||
| input: string[]; | ||
| } & ({ |
InferredFlagstoInterfacesexport. See details belowFlags.customto replaceFlags.build. See details belowdefaultproperty always expecting a single item even ifmultipleis set totruePotential Breaks
In order to switch the expected type of
defaultbased onmultipletheInterfaces.OptionFlagno longer has statically known members. Downstream, this means that any interface that extendsInterfaces.OptionFlagwill fail to compile. To fix this, you just need to switch to using atype:Before
After
Additionally, the same change may cause custom flags that use
buildto fail compilation if you purposely override thedefault. For example:This fails because the
defaulttype doesn't know what the value ofbaseProps.multipleis. In order to fix this you need to add anif/elselike so:InferredFlags
Infer the flags that are returned by
Command.parse. This is useful for when you want to assign the flags as a class property.Flags.custom
Custom flags built using
Flags.buildwere not properly typed unless you specified a variety of function overloads (example).To replace that, we've introduced
Flags.customwhich allows us to define a custom with correct typing and no function overloading required:Before
After