meow icon indicating copy to clipboard operation
meow copied to clipboard

[TS] Any way to predefine the flags then typecheck them in options?

Open whitetrefoil opened this issue 5 years ago • 8 comments

Currently the type of flags are difficult to predefine, it'll be easier to write the meow(..., ...) function then get the returned type.

But I'm trying to predefine the flags' type then use it to typecheck the meow() function. e.g.:

// interfaces/config.ts

export interface IFlags {
  flag1: string;
  flag2: boolean;
  flag3: number;
}

export interface IConfig {
  argv: meow.IResult<IFlags>; // similar to meow.Result but pass in flag type not flag def
  some: string;
  other: boolean;
  configs: number[];
}
// config.ts

import {IFlags, IConfig} from './interfaces/config.ts';

const argv = anotherWayToMeow<IFlags>( // similar to current meow() but pass in flag type not def
  `Usage: xxxxxxx`,
  {
    flags: {
      // better to have typecheck here,
      // if not at least can predefine the result flags
      flag1: { alias: 'a', type: 'string' },
      flag2: { alias: 'b' }, // error because missing type: 'boolean'
      // error because missing flag3
    },
  },
)

const some = 'xxxx';
const other = process.env.MY_ENV === 'other';
const configs = [1,2,3];

const config: IConfig = { argv, some, other, configs };

export default config;

whitetrefoil avatar Dec 09 '19 02:12 whitetrefoil

Why do you need to predefine them? The Meow types are smart enough to use the correct types depending on what you specify in the flag.type property. See: https://github.com/sindresorhus/meow/commit/3e05a2ee38559b848b487d3fae892b271dfb5908

// @NiGhTTraX

sindresorhus avatar Dec 16 '19 11:12 sindresorhus

That's because:

  1. I want to share the type of flags to other files.
  2. In my team, we're used to design a module/file (result in interfaces & type aliases) before coding it.
  3. Personally, I'm used to firstly write down the type I want then use it to type-check my impl. (this is the reason I use ts instead of js)

whitetrefoil avatar Dec 16 '19 23:12 whitetrefoil

@whitetrefoil you don't need to pass a generic type to meow if you can define your expected result type:

type Flags = {
  foo: number;
}

const cli: { flags: Flags } = meow({
  flags: {
    foo: { type: 'number' }
  }
});

You would get a type error if you tried to use type: 'string' instead because the result wouldn't be assignable to your type.

NiGhTTraX avatar Dec 17 '19 06:12 NiGhTTraX

@NiGhTTraX That's a nice workaround. I'll use it before I find a better way (if there is). Thanks a lot!

whitetrefoil avatar Dec 17 '19 09:12 whitetrefoil

The solution suggested by @NiGhTTraX sounds like the proper one to me.

It's even the one used in meow's type tests:

https://github.com/sindresorhus/meow/blob/629af48c24a2f19636512b2f532cfcd9419f9be1/index.test-d.ts#L8-L16

voxpelli avatar Jun 18 '20 11:06 voxpelli

Would this not be solved by a very simple export of AnyFlags type? Type errors would be show at the same location as the flags definition, rather then where they are passed.

// file_1.ts
const flags: AnyFlags = {
  unicorn: {
    type: 'string',
  },
};

// file_2.ts
meow(flags);

andrewmclagan avatar May 28 '24 22:05 andrewmclagan