arrify
Convert any value to an array, safely handling null, undefined, strings, and iterables.
Repository Health
Technical Analysis
arrify is a tiny utility from Sindre Sorhus that normalizes any JavaScript value into an array. It treats null and undefined as an empty array, passes existing arrays through unchanged, wraps strings as a single-element array instead of splitting them into characters, and spreads any iterable (a Set, a Map, a generator) into a proper array via Symbol.iterator. Everything else falls back to a single-element array.
The package is distributed as a single ESM file with bundled TypeScript definitions that use conditional types to infer the precise return type for each input shape — arrify('x') types as [string], arrify(mySet) types as T[], and so on. It has no runtime dependencies and is commonly reached for whenever an API needs to accept either a single value or a collection of values.
What You Get
- A single default-exported
arrify()function with no configuration or options object. - Bundled TypeScript definitions with conditional types that infer the exact return type per input shape.
- ESM-only distribution (
type: module, singleexportsentry) with zero runtime dependencies. - Consistent
null/undefinedhandling — both normalize to an empty array rather than throwing.
Common Use Cases
- Normalizing function arguments - Library authors accepting
string | string[]-style options callarrify()once and iterate without branching. - CLI flag handling - CLI tools that let a flag be passed once or repeated can arrify the parsed value into a consistent array.
- Safe optional-array defaults - Code paths that may receive
null/undefinedfor an “items” field arrify it into[]instead of null-checking everywhere. - Converting Set/Map results to arrays - Consumers of Set- or Map-based APIs arrify the result for
.map()/.filter()chaining.
Under The Hood
Architecture
The entire package is one exported function in index.js that runs a short sequence of type checks — null/undefined first, then Array.isArray, then typeof value === 'string', then a Symbol.iterator check for other iterables, with a final fallback that wraps the value in a single-element array. There are no internal layers, no dependency injection, and no state; the only “architecture” is the ordering of these checks, which matters because strings are themselves iterable and must be special-cased before the generic iterable branch.
Tech Stack
The runtime code has zero dependencies and ships as native ESM ("type": "module", single exports field, Node >=12 engine constraint). Tooling is entirely dev-time: ava for unit tests, tsd for type-level assertions against the hand-written index.d.ts, and xo (Sindre Sorhus’s opinionated ESLint preset) for linting — all invoked from a single npm test script. No bundler or build step is needed since the published files are the same plain JS/.d.ts files in the repo.
Code Quality
Test coverage in test.js exercises the main branches (string, Map, Set, null, undefined, and array-identity preservation) using ava, and index.test-d.ts separately asserts the inferred TypeScript types for a wide range of input shapes via tsd. A GitHub Actions workflow runs this full suite across Node 12, 14, and 16 on every push and PR. The function itself has no error handling because it cannot fail — every input maps to some array output — and naming is minimal and clear given the tiny surface area.
What Makes It Unique
The runtime behavior itself is a standard normalization utility comparable to Lodash’s castArray. What sets it apart is the type-level precision: the bundled conditional types compute the literal return type for each input variant (a string input types as a one-tuple, an array passes through as-is, an iterable resolves to its element type), which is more exact than most similarly small utilities bother to provide.