Skip to content

Commit

Permalink
Add type information for flags (#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
NiGhTTraX authored and sindresorhus committed Nov 18, 2019
1 parent 499d186 commit 3e05a2e
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 41 deletions.
24 changes: 17 additions & 7 deletions index.d.ts
Expand Up @@ -2,7 +2,7 @@ import {PackageJson} from 'type-fest';
import {Options as MinimistOptions} from 'minimist-options';

declare namespace meow {
interface Options {
interface Options<Flags extends MinimistOptions> {
/**
Define argument flags.
Expand All @@ -23,7 +23,7 @@ declare namespace meow {
}
```
*/
readonly flags?: MinimistOptions;
readonly flags?: Flags;

/**
Description to show above the help text. Default: The package.json `"description"` property.
Expand Down Expand Up @@ -159,7 +159,17 @@ declare namespace meow {
readonly hardRejection?: boolean;
}

interface Result {
type TypedFlags<Flags extends MinimistOptions> = {
[F in keyof Flags]: Flags[F] extends {type: 'number'}
? number
: Flags[F] extends {type: 'string'}
? string
: Flags[F] extends {type: 'boolean'}
? boolean
: unknown;
};

interface Result<Flags extends MinimistOptions> {
/**
Non-flag arguments.
*/
Expand All @@ -168,12 +178,12 @@ declare namespace meow {
/**
Flags converted to camelCase excluding aliases.
*/
flags: {[name: string]: unknown};
flags: TypedFlags<Flags> & {[name: string]: unknown};

/**
Flags converted camelCase including aliases.
*/
unnormalizedFlags: {[name: string]: unknown};
unnormalizedFlags: TypedFlags<Flags> & {[name: string]: unknown};

/**
The `package.json` object.
Expand Down Expand Up @@ -236,7 +246,7 @@ const cli = meow(`
foo(cli.input[0], cli.flags);
```
*/
declare function meow(helpMessage: string, options?: meow.Options): meow.Result;
declare function meow(options?: meow.Options): meow.Result;
declare function meow<Flags extends MinimistOptions>(helpMessage: string, options?: meow.Options<Flags>): meow.Result<Flags>;
declare function meow<Flags extends MinimistOptions>(options?: meow.Options<Flags>): meow.Result<Flags>;

export = meow;
72 changes: 38 additions & 34 deletions index.test-d.ts
@@ -1,48 +1,52 @@
import {expectType} from 'tsd';
import {expectAssignable, expectType} from 'tsd';
import {PackageJson} from 'type-fest';
import meow = require('.');
import {Result} from '.';

expectType<Result>(meow('Help text'));
expectType<Result>(meow('Help text', {hardRejection: false}));
expectType<Result>(
meow({
flags: {
unicorn: {
type: 'boolean',
alias: 'u'
},
fooBar: {
type: 'string',
default: 'foo'
}
}
})
expectType<Result<never>>(meow('Help text'));
expectType<Result<never>>(meow('Help text', {hardRejection: false}));
expectAssignable<{flags: {foo: number}}>(
meow({flags: {foo: {type: 'number'}}})
);
expectType<Result>(meow({description: 'foo'}));
expectType<Result>(meow({description: false}));
expectType<Result>(meow({help: 'foo'}));
expectType<Result>(meow({help: false}));
expectType<Result>(meow({version: 'foo'}));
expectType<Result>(meow({version: false}));
expectType<Result>(meow({autoHelp: false}));
expectType<Result>(meow({autoVersion: false}));
expectType<Result>(meow({pkg: {foo: 'bar'}}));
expectType<Result>(meow({argv: ['foo', 'bar']}));
expectType<Result>(meow({inferType: true}));
expectType<Result>(meow({booleanDefault: true}));
expectType<Result>(meow({booleanDefault: null}));
expectType<Result>(meow({booleanDefault: undefined}));
expectType<Result>(meow({hardRejection: false}));
expectAssignable<{flags: {foo: string}}>(
meow({flags: {foo: {type: 'string'}}})
);
expectAssignable<{flags: {foo: boolean}}>(
meow({flags: {foo: {type: 'boolean'}}})
);
expectType<Result<never>>(meow({description: 'foo'}));
expectType<Result<never>>(meow({description: false}));
expectType<Result<never>>(meow({help: 'foo'}));
expectType<Result<never>>(meow({help: false}));
expectType<Result<never>>(meow({version: 'foo'}));
expectType<Result<never>>(meow({version: false}));
expectType<Result<never>>(meow({autoHelp: false}));
expectType<Result<never>>(meow({autoVersion: false}));
expectType<Result<never>>(meow({pkg: {foo: 'bar'}}));
expectType<Result<never>>(meow({argv: ['foo', 'bar']}));
expectType<Result<never>>(meow({inferType: true}));
expectType<Result<never>>(meow({booleanDefault: true}));
expectType<Result<never>>(meow({booleanDefault: null}));
expectType<Result<never>>(meow({booleanDefault: undefined}));
expectType<Result<never>>(meow({hardRejection: false}));

const result = meow('Help text');
const result = meow('Help text', {
flags: {
foo: {type: 'boolean', alias: 'f'},
'foo-bar': {type: 'number'}
}}
);

expectType<string[]>(result.input);
expectType<{[name: string]: unknown}>(result.flags);
expectType<{[name: string]: unknown}>(result.unnormalizedFlags);
expectType<PackageJson>(result.pkg);
expectType<string>(result.help);

expectType<boolean>(result.flags.foo);
expectType<boolean>(result.unnormalizedFlags.foo);
expectType<unknown>(result.unnormalizedFlags.f);
expectType<number>(result.unnormalizedFlags['foo-bar']);
expectType<unknown>(result.flags.fooBar);

result.showHelp();
result.showHelp(1);
result.showVersion();

0 comments on commit 3e05a2e

Please sign in to comment.