{"id":13902982,"url":"https://github.com/privatenumber/type-flag","last_synced_at":"2026-04-18T14:11:04.404Z","repository":{"id":41846270,"uuid":"396199803","full_name":"privatenumber/type-flag","owner":"privatenumber","description":"⛳️ Typed command-line arguments parser for Node.js","archived":false,"fork":false,"pushed_at":"2026-04-15T11:20:44.000Z","size":1562,"stargazers_count":209,"open_issues_count":6,"forks_count":4,"subscribers_count":1,"default_branch":"develop","last_synced_at":"2026-04-15T13:33:05.101Z","etag":null,"topics":["argument-parser","argv","cli","cli-flags","command-line","flag","minimist","node","nodejs","parse","parser","typed","typescript","yargs"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/privatenumber.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"privatenumber"}},"created_at":"2021-08-15T03:14:41.000Z","updated_at":"2026-04-12T07:18:32.000Z","dependencies_parsed_at":"2025-11-05T17:09:47.519Z","dependency_job_id":null,"html_url":"https://github.com/privatenumber/type-flag","commit_stats":{"total_commits":138,"total_committers":1,"mean_commits":138.0,"dds":0.0,"last_synced_commit":"eabee3f2f8c7e85b10452ef000710d753f09cc5f"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/privatenumber/type-flag","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/privatenumber%2Ftype-flag","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/privatenumber%2Ftype-flag/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/privatenumber%2Ftype-flag/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/privatenumber%2Ftype-flag/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/privatenumber","download_url":"https://codeload.github.com/privatenumber/type-flag/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/privatenumber%2Ftype-flag/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31971540,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T00:39:45.007Z","status":"online","status_checked_at":"2026-04-18T02:00:07.018Z","response_time":103,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["argument-parser","argv","cli","cli-flags","command-line","flag","minimist","node","nodejs","parse","parser","typed","typescript","yargs"],"created_at":"2024-08-06T22:01:32.410Z","updated_at":"2026-04-18T14:11:04.395Z","avatar_url":"https://github.com/privatenumber.png","language":"TypeScript","funding_links":["https://github.com/sponsors/privatenumber","https://github.com/sponsors/privatenumber/sponsorships?tier_id=398771","https://github.com/sponsors/privatenumber/sponsorships?tier_id=397608"],"categories":["cli"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\t\u003cimg width=\"100\" src=\".github/logo.webp\"\u003e\n\u003c/p\u003e\n\u003ch1 align=\"center\"\u003e\n\ttype-flag\n\t\u003cbr\u003e\n\t\u003ca href=\"https://npm.im/type-flag\"\u003e\u003cimg src=\"https://badgen.net/npm/v/type-flag\"\u003e\u003c/a\u003e \u003ca href=\"https://npm.im/type-flag\"\u003e\u003cimg src=\"https://badgen.net/npm/dm/type-flag\"\u003e\u003c/a\u003e\t\n\u003c/h1\u003e\n\nStrongly typed command-line arguments parser.\n\nNo dependencies \u0026 tree-shakable (Max 1.4 kB).\n\n→ [Try it out online](https://stackblitz.com/edit/type-flag-demo?devtoolsheight=50\u0026file=src/type-flag.ts\u0026view=editor)\n\u003c/div\u003e\n\n\n\n\u003e [!TIP]\n\u003e **Looking for something more robust? 👀**\n\u003e\n\u003e Try [**Cleye**](https://github.com/privatenumber/cleye)—a CLI development tool powered by _type-flag_.\n\u003e\n\u003e In addition to flag parsing, it supports argument parsing and has a beautiful `--help` documentation generator.\n\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"https://github.com/sponsors/privatenumber/sponsorships?tier_id=398771\"\u003e\u003cimg width=\"412\" src=\"https://raw.githubusercontent.com/privatenumber/sponsors/master/banners/assets/donate.webp\"\u003e\u003c/a\u003e\n\t\u003ca href=\"https://github.com/sponsors/privatenumber/sponsorships?tier_id=397608\"\u003e\u003cimg width=\"412\" src=\"https://raw.githubusercontent.com/privatenumber/sponsors/master/banners/assets/sponsor.webp\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\u003csup\u003e\u003ci\u003eAlready a sponsor?\u003c/i\u003e Join the discussion in the \u003ca href=\"https://github.com/pvtnbr/tsx\"\u003eDevelopment repo\u003c/a\u003e!\u003c/sup\u003e\u003c/p\u003e\n\n## 🚀 Install\n\n```bash\nnpm i type-flag\n```\n\n## 🚦 Quick start\n\nLet's say you want to create a script with the following usage:\n```\n$ my-script --name John --age 20\n```\n\n### typeFlag\n\nHere's how easy it is with _type-flag_:\n```ts\nimport { typeFlag } from 'type-flag'\n\nconst parsed = typeFlag({\n    name: String,\n    age: {\n        type: Number,\n        alias: 'a'\n    }\n})\n\nconsole.log(parsed.flags.name) // 'John'\nconsole.log(parsed.flags.age) // 20\n```\n\nYou can also get unknown flags and arguments from the `parsed` object:\n```ts\n// object of unknown flags passed in\nconsole.log(parsed.unknownFlags)\n\n// arguments\nconsole.log(parsed._)\n```\n\n### getFlag\n\n_Want something even simpler?_\n\n_type-flag_ also exports a `getFlag` function that returns a single flag value.\n\n```ts\nimport { getFlag } from 'type-flag'\n\nconst name = getFlag('--name', String)\nconst age = getFlag('-a,--age', Number)\n\nconsole.log(name) // 'John'\nconsole.log(age) // 20\n```\n\n\nThese are quick demos but _type-flag_ can do so much more:\n- Accept multiple flag values\n- Flag operators (e.g. `=`) for explicitly passing in a value\n- Parse unknown flags\n- Parse alias groups (e.g. `-abc`)\n\nKeep reading to learn more!\n\n## 🧑‍💻 Usage\n### Defining flags\nPass in an object where the key is the flag name and the value is the flag type—a parser function that takes in a string and parses it to that type. Default JavaScript constructors should be able to cover most use-cases: [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/String), [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/Number), [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean/Boolean), etc.\n\nThe value can also be an object with the `type` property as the flag type.\n\n```ts\ntypeFlag({\n    // Short-hand\n    stringFlag: String,\n    numberFlag: Number,\n    booleanFlag: Boolean,\n\n    // Object syntax:\n    stringFlag: {\n        type: String\n    }\n})\n```\n\n#### Array type\nTo accept multiple values of a flag, wrap the type with an array:\n\n```ts\nconst parsed = typeFlag({\n    myFlag: [String]\n})\n\n// $ node ./cli --my-flag A --my-flag B\nparsed.flags.myFlag // =\u003e ['A', 'B']\n```\n\n#### Aliases\nFlags are often given single-character aliases for shorthand usage (eg. `--help` to `-h`). To give a flag an alias, use the object syntax and set the `alias` property to a single-character name.\n\n```ts\ntypeFlag({\n    myFlag: {\n        type: String,\n        alias: 'm'\n    }\n})\n\n// $ node ./cli -m hello\nparsed.flags.myFlag // =\u003e 'hello'\n```\n\n#### Single-character flag names\nA flag name can itself be a single character. It matches `-x` but not `--x`.\n\n```ts\ntypeFlag({\n    x: Number,\n    y: Number\n})\n\n// $ node ./cli -x 10 -y 20\nparsed.flags.x // =\u003e 10\nparsed.flags.y // =\u003e 20\n```\n\nBecause `--x` is reserved for long flags, you can declare both a single-character and a long-form flag as independent entries — useful when the two forms should behave differently (e.g. `rg`'s `-h` shows short help, `--help` shows full help):\n\n```ts\ntypeFlag({\n    h: Boolean,\n    help: Boolean\n})\n```\n\nA single-character flag cannot have an `alias` (it already IS a short flag).\n\n**Single-character names vs aliases:** Both produce short flags that can appear in groups — `-ab`, `-av`, or any mix — regardless of whether each character came from a name or an alias. The difference is where the value lands: a name creates its own key in `flags`, while an alias feeds into the target flag's key. Use a single-character name when the short form IS the flag (`-x`/`-y` coordinates, `-h` vs `--help`); use an alias when `--verbose` and `-v` should set the same value.\n\n#### Default values\nFlags that are not passed in will default to being `undefined`. To set a different default value, use the object syntax and pass in a value as the `default` property. When a default is provided, the return type will reflect that instead of `undefined`.\n\nWhen using mutable values (eg. objects/arrays) as a default, pass in a function that creates it to avoid mutation-related bugs.\n\n```ts\nconst parsed = typeFlag({\n    someNumber: {\n        type: Number,\n        default: 1\n    },\n\n    manyNumbers: {\n        type: [Number],\n\n        // Use a function to return an object or array\n        default: () =\u003e [1, 2, 3]\n    }\n})\n```\n\nTo get `undefined` in the parsed flag type, make sure [`strict`](https://www.typescriptlang.org/tsconfig/#strict) or [`strictNullChecks`](https://www.typescriptlang.org/tsconfig#strictNullChecks) is enabled.\n\n### kebab-case flags mapped to camelCase\nWhen passing in the flags, they can be in kebab-case and will automatically map to the camelCase equivalent.\n```ts\nconst parsed = typeFlag({\n    someString: [String]\n})\n\n// $ node ./cli --someString hello --some-string world\nparsed.flags.someString // =\u003e ['hello', 'world']\n```\n\n### Unknown flags\nWhen unrecognized flags are passed in, they are interpreted as a boolean, or a string if explicitly passed in. Unknown flags are not converted to camelCase to allow for accurate error handling.\n\n```ts\nconst parsed = typeFlag({})\n\n// $ node ./cli --some-flag --some-flag=1234\nparsed.unknownFlags // =\u003e { 'some-flag': [true, '1234'] }\n```\n\n### Arguments\nArguments are values passed in that are not associated with any flags. All arguments are stored in the `_` property.\n\nEverything after `--` (end-of-flags) is treated as an argument (including flags) and will be stored in the `_['--']` property.\n\n```ts\nconst parsed = typeFlag({\n    myFlag: [String]\n})\n\n// $ node ./cli --my-flag value arg1 -- --my-flag world\nparsed.flags.myFlag // =\u003e ['value']\nparsed._ // =\u003e ['arg1', '--my-flag', 'world']\nparsed._['--'] // =\u003e ['--my-flag', 'world']\n```\n\n### Flag value delimiters\nThe characters `=`, `:` and `.` are reserved for delimiting the value from the flag.\n\n```sh\n$ node ./cli --flag=value --flag:value --flag.value\n```\n\nThis allows for usage like `--flag:key=value` or `--flag.property=value` to be possible.\n\n### Mutated argv array\n\nWhen `type-flag` iterates over the argv array, it removes the tokens it parses out via mutation.\n\nBy default, `type-flag` works on a new copy of `process.argv.slice(2)` so this doesn't have any side-effects. But if you want to leverage this behavior to extract certain flags and arguments, you can pass in your own copy of `process.argv.slice(2)`.\n\nThis may be useful for filtering out certain flags before passing down the `argv` to a child process.\n\n#### Ignoring unknown flags\nSometimes it may be undesirable to parse unknown flags. In these cases, you can ignore them so they're left unparsed in the `argv` array.\n\n```ts\nconst argv = process.argv.slice(2)\nconst parsed = typeFlag(\n    {},\n    argv,\n    {\n        ignore: type =\u003e type === 'unknown-flag'\n    }\n)\n\n// $ node ./cli --unknown=hello\nparsed._ // =\u003e []\nargv // =\u003e ['--unknown=hello']\n```\n\n#### Ignoring everything after the first argument\n\nSimilarly to how Node.js only reads flags passed in before the first argument, _type-flag_ can be configured to ignore everything after the first argument.\n\n```ts\nconst argv = process.argv.slice(2)\n\nlet stopParsing = false\nconst parsed = typeFlag(\n    {\n        myFlag: [Boolean]\n    },\n    argv,\n    {\n        ignore: (type) =\u003e {\n            if (stopParsing) {\n                return true\n            }\n            const isArgument = type === 'argument'\n            if (isArgument) {\n                stopParsing = isArgument\n                return stopParsing\n            }\n        }\n    }\n)\n\n// $ node ./cli --my-flag ./file.js --my-flag\nparsed.flags.myFlag // =\u003e [true]\nargv // =\u003e ['./file.js', '--my-flag']\n```\n\n\n## 👨🏻‍🏫 Examples\n\n### Custom flag type\nBasic types can be set using [built-in functions in JavaScript](https://www.w3schools.com/js/js_object_constructors.asp#:~:text=Built-in%20JavaScript%20Constructors), but sometimes you want to a new type, narrow the type, or add validation.\n\nTo create a new type, simply declare a function that accepts a string argument and returns the parsed value with the expected type.\n\nIn this example, the `size` flag is enforced to be either `small`, `medium` or `large`.\n```ts\nconst possibleSizes = ['small', 'medium', 'large'] as const\n\ntype Sizes = typeof possibleSizes[number]\n\nconst Size = (size: Sizes) =\u003e {\n    if (!possibleSizes.includes(size)) {\n        throw new Error(`Invalid size: \"${size}\"`)\n    }\n\n    return size\n}\n\nconst parsed = typeFlag({\n    size: Size\n})\n```\n\n`parsed` resolves to the following type:\n```ts\ntype Parsed = {\n    flags: {\n        size: 'small' | 'medium' | 'large' | undefined\n    }\n    // ...\n}\n```\n\n### Optional value flag\n\nTo create a string flag that acts as a boolean when nothing is passed in, create a custom type that returns both types.\n\n```ts\nconst OptionalString = (value: string) =\u003e {\n    if (!value) {\n        return true\n    }\n\n    return value\n}\n\nconst parsed = typeFlag({\n    string: OptionalString\n})\n\n// $ node ./cli --string\nparsed.flags.string // =\u003e true\n\n// $ node ./cli --string hello\nparsed.flags.string // =\u003e 'hello'\n```\n\n### Accepting flag values with `=` in it\nIn use-cases where flag values contain `=`, you can use `:` instead. This allows flags like `--define:K=V`.\n\n```ts\nconst parsed = typeFlag({\n    define: String\n})\n\n// $ node ./cli --define:key=value\nparsed.flags.define // =\u003e 'key=value'\n```\n\n### Dot-nested flags\n```ts\ntype Environment = {\n    TOKEN?: string\n    CI?: boolean\n}\n\nconst EnvironmentObject = (value: string): Environment =\u003e {\n    const [propertyName, propertyValue] = value.split('=')\n    return {\n        [propertyName]: propertyValue || true\n    }\n}\n\nconst parsed = typeFlag({\n    env: [EnvironmentObject]\n})\n\nconst env = parsed.flags.env.reduce(\n    (agg, next) =\u003e Object.assign(agg, next),\n    {}\n)\n\n// $ node ./cli --env.TOKEN=123 --env.CI\nenv // =\u003e { TOKEN: 123, CI: true }\n```\n\n### Inverting a boolean\n\nEnable `booleanNegation` to support `--no-` prefixed flags for boolean negation:\n\n```ts\nconst argv = process.argv.slice(2)\nconst parsed = typeFlag({\n    verbose: Boolean\n}, argv, { booleanNegation: true })\n\n// $ node ./cli --no-verbose\nparsed.flags.verbose // =\u003e false\n```\n\nLast-wins semantics apply naturally:\n```ts\n// $ node ./cli --verbose --no-verbose\nparsed.flags.verbose // =\u003e false\n\n// $ node ./cli --no-verbose --verbose\nparsed.flags.verbose // =\u003e true\n```\n\nThe `--no-` prefix only applies to flags defined as `Boolean` in the schema. For non-boolean or unregistered flags, `--no-\u003cname\u003e` is treated as an unknown flag.\n\nYou can also invert a boolean by passing `false` explicitly with the `=` operator (or any other value delimiter):\n\n```ts\n// $ node ./cli --verbose=false\nparsed.flags.verbose // =\u003e false\n```\n\nWithout explicitly specifying the flag value via `=`, `false` will be parsed as a separate argument:\n\n```ts\n// $ node ./cli --verbose false\nparsed.flags.verbose // =\u003e true\nparsed._ // =\u003e ['false']\n```\n\n### Counting flags\nTo create an API where passing in a flag multiple times increases a count (a pretty common one is `-vvv`), you can use an array-boolean type and count the size of the array:\n\n```ts\nconst parsed = typeFlag({\n    verbose: {\n        type: [Boolean],\n        alias: 'v'\n    }\n})\n\n// $ node ./cli -vvv\nparsed.flags.verbose.length // =\u003e 3\n```\n\n## ⚙️ API\n\n### typeFlag(flagSchema, argv, options)\n\nReturns an object with the shape:\n```ts\ntype Parsed = {\n    flags: {\n        [flagName: string]: InferredType\n    }\n    unknownFlags: {\n        [flagName: string]: (string | boolean)[]\n    }\n    _: string[]\n}\n```\n\n#### flagSchema\nType:\n```ts\ntype TypeFunction = (...args: any[]) =\u003e unknown\n\ntype FlagSchema = {\n    [flagName: string]: TypeFunction | [TypeFunction] | {\n        type: TypeFunction | [TypeFunction]\n        alias?: string\n        default?: unknown\n    }\n}\n```\n\n\nAn object containing flag schema definitions. Where the key is the flag name, and the value is either the type function or an object containing the type function and/or alias.\n\n#### argv\nType: `string[]`\n\nDefault: `process.argv.slice(2)`\n\nThe argv array to parse. The array is mutated to remove the parsed flags.\n\n#### options\n\nType:\n```ts\ntype Options = {\n    // Callback to skip parsing on certain argv tokens\n    ignore?: (\n        type: 'known-flag' | 'unknown-flag' | 'argument',\n        flagOrArgv: string,\n        value: string | undefined\n    ) =\u003e boolean | void\n\n    // Enable --no-\u003cflag\u003e negation for boolean flags\n    booleanNegation?: boolean\n}\n```\n\n---\n\n### getFlag(flagNames, flagType, argv)\n\n#### flagNames\nType: `string`\n\nA comma-separated list of flag names to parse.\n\n#### flagType\nType:\n```ts\ntype TypeFunction = (...args: any[]) =\u003e unknown\n\ntype FlagType = TypeFunction | [TypeFunction]\n```\n\nA function to parse the flag value. Wrap the function in an array to retrieve all values.\n\n#### argv\nType: `string[]`\n\nDefault: `process.argv.slice(2)`\n\nThe argv array to parse. The array is mutated to remove the parsed flags.\n\n## Agent Skills\n\nThis package ships with a built-in [agent skill](https://agentskills.io) for AI coding assistants. Set up [`skills-npm`](https://github.com/antfu/skills-npm) in your project to use it.\n\n## Sponsors\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"https://github.com/sponsors/privatenumber\"\u003e\n\t\t\u003cimg src=\"https://cdn.jsdelivr.net/gh/privatenumber/sponsors/sponsorkit/sponsors.svg\"\u003e\n\t\u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprivatenumber%2Ftype-flag","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprivatenumber%2Ftype-flag","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprivatenumber%2Ftype-flag/lists"}