Skip to content

Commit e38789f

Browse files
voxpellisindresorhus
andauthoredAug 10, 2020
Improve flags types to acknowledge isMultiple and isRequired options (#154)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
1 parent fa2a374 commit e38789f

File tree

4 files changed

+66
-11
lines changed

4 files changed

+66
-11
lines changed
 

‎index.d.ts

+18-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ declare namespace meow {
2525
type BooleanFlag = Flag<'boolean', boolean>;
2626
type NumberFlag = Flag<'number', number>;
2727

28-
type AnyFlags = {[key: string]: StringFlag | BooleanFlag | NumberFlag};
28+
type AnyFlag = StringFlag | BooleanFlag | NumberFlag;
29+
type AnyFlags = {[key: string]: AnyFlag};
2930

3031
interface Options<Flags extends AnyFlags> {
3132
/**
@@ -195,14 +196,26 @@ declare namespace meow {
195196
readonly hardRejection?: boolean;
196197
}
197198

198-
type TypedFlags<Flags extends AnyFlags> = {
199-
[F in keyof Flags]: Flags[F] extends {type: 'number'}
199+
type TypedFlag<Flag extends AnyFlag> =
200+
Flag extends {type: 'number'}
200201
? number
201-
: Flags[F] extends {type: 'string'}
202+
: Flag extends {type: 'string'}
202203
? string
203-
: Flags[F] extends {type: 'boolean'}
204+
: Flag extends {type: 'boolean'}
204205
? boolean
205206
: unknown;
207+
208+
type PossiblyOptionalFlag<Flag extends AnyFlag, FlagType> =
209+
Flag extends {isRequired: true}
210+
? FlagType
211+
: Flag extends {default: any}
212+
? FlagType
213+
: FlagType | undefined;
214+
215+
type TypedFlags<Flags extends AnyFlags> = {
216+
[F in keyof Flags]: Flags[F] extends {isMultiple: true}
217+
? PossiblyOptionalFlag<Flags[F], Array<TypedFlag<Flags[F]>>>
218+
: PossiblyOptionalFlag<Flags[F], TypedFlag<Flags[F]>>
206219
};
207220

208221
interface Result<Flags extends AnyFlags> {

‎index.test-d.ts

+18-6
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,21 @@ import {Result} from '.';
66
expectType<Result<never>>(meow('Help text'));
77
expectType<Result<never>>(meow('Help text', {hardRejection: false}));
88
expectAssignable<{flags: {foo: number}}>(
9-
meow({flags: {foo: {type: 'number'}}})
9+
meow({flags: {foo: {type: 'number', isRequired: true}}})
1010
);
1111
expectAssignable<{flags: {foo: string}}>(
12-
meow({flags: {foo: {type: 'string'}}})
12+
meow({flags: {foo: {type: 'string', isRequired: true}}})
1313
);
1414
expectAssignable<{flags: {foo: boolean}}>(
15+
meow({flags: {foo: {type: 'boolean', isRequired: true}}})
16+
);
17+
expectAssignable<{flags: {foo: number | undefined}}>(
18+
meow({flags: {foo: {type: 'number'}}})
19+
);
20+
expectAssignable<{flags: {foo: string | undefined}}>(
21+
meow({flags: {foo: {type: 'string'}}})
22+
);
23+
expectAssignable<{flags: {foo: boolean | undefined}}>(
1524
meow({flags: {foo: {type: 'boolean'}}})
1625
);
1726
expectType<Result<never>>(meow({description: 'foo'}));
@@ -34,21 +43,24 @@ const result = meow('Help text', {
3443
flags: {
3544
foo: {type: 'boolean', alias: 'f'},
3645
'foo-bar': {type: 'number'},
37-
bar: {type: 'string', default: ''}
46+
bar: {type: 'string', default: ''},
47+
abc: {type: 'string', isMultiple: true}
3848
}
3949
});
4050

4151
expectType<string[]>(result.input);
4252
expectType<PackageJson>(result.pkg);
4353
expectType<string>(result.help);
4454

45-
expectType<boolean>(result.flags.foo);
55+
expectType<boolean | undefined>(result.flags.foo);
4656
expectType<unknown>(result.flags.fooBar);
4757
expectType<string>(result.flags.bar);
48-
expectType<boolean>(result.unnormalizedFlags.foo);
58+
expectType<string[] | undefined>(result.flags.abc);
59+
expectType<boolean | undefined>(result.unnormalizedFlags.foo);
4960
expectType<unknown>(result.unnormalizedFlags.f);
50-
expectType<number>(result.unnormalizedFlags['foo-bar']);
61+
expectType<number | undefined>(result.unnormalizedFlags['foo-bar']);
5162
expectType<string>(result.unnormalizedFlags.bar);
63+
expectType<string[] | undefined>(result.unnormalizedFlags.abc);
5264

5365
result.showHelp();
5466
result.showHelp(1);

‎test/test.js

+11
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,17 @@ test('isMultiple - handles multi-word flag name', t => {
510510
});
511511
});
512512

513+
test('isMultiple - handles non-set flags correctly', t => {
514+
t.deepEqual(meow({
515+
argv: [],
516+
flags: {
517+
foo: {
518+
isMultiple: true
519+
}
520+
}
521+
}).flags, {});
522+
});
523+
513524
if (NODE_MAJOR_VERSION >= 14) {
514525
test('supports es modules', async t => {
515526
try {

‎tsconfig.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"files": [
3+
"index.d.ts",
4+
"index.test-d.ts",
5+
],
6+
"compilerOptions": {
7+
"strict": true,
8+
"jsx": "react",
9+
"target": "es2018",
10+
"lib": [
11+
"es2018"
12+
],
13+
"module": "commonjs",
14+
"moduleResolution": "node",
15+
"noImplicitAny": true,
16+
"strictNullChecks": true,
17+
"noUnusedLocals": true
18+
}
19+
}

0 commit comments

Comments
 (0)
Please sign in to comment.