anyfamily API reference
Overview
anyfamily is the whole any* family in one install: eight micro Intl tools behind a single import.
It has no API of its own. The published module is a re-export — under half a kilobyte of ESM that forwards eight names and their types. Every option, every default and every edge case belongs to the package the name came from, so this page is a map rather than a reference: each row below links to the real one.
import { anywhen, anyamount, anyword } from 'anyfamily'
anywhen(post.createdAt, { mode: 'relative' }) // "3 hours ago"
anyamount(1999, { mode: 'currency', currency: 'EUR' }) // "€1,999.00"
anyword.count('世界 test') // 2Install
npm install anyfamily
# or
pnpm add anyfamily
# or
yarn add anyfamilyNode 18+, ESM and CJS builds with types for both. The eight packages come along as dependencies; none of them depends on anything else.
Exports
Eight names, one per package. The bare call does the job; the extras hang off the same name. Follow a row for its options, its modes and its edge cases.
Dates and times — relative when near, calendar labels for recent days, absolute when far.
anywhen.parts — over Intl.DateTimeFormat
Numbers, currency and units, compact by default.
anyamount.parts · anyamount.symbol — over Intl.NumberFormat
An array into a sentence, joined and sorted the way the locale does it.
anymany.parts — over Intl.ListFormat (+ Collator)
Region, language, script, currency and calendar codes into readable names — plus the flag Intl leaves out.
anyaround.info — over Intl.DisplayNames
Durations, from milliseconds, ISO 8601, shorthand, a record or two dates.
anylong.parts · anylong.supported — over Intl.DurationFormat
Cardinal and ordinal plurals, including the locales with six forms.
anyplural.parts — over Intl.PluralRules
Words, graphemes and sentences — counted and cut the way people see them.
anyword.parts · anyword.count · anyword.truncate · anyword.supported — over Intl.Segmenter
How a locale behaves: direction, week start, weekend, calendars, zones, hour cycle, digits.
anylocale.supported — over Intl.Locale info
.parts means the same thing everywhere: the formatted output as an array of typed pieces, for when you need to style the currency symbol apart from the digits, or the unit apart from the number.
One shape everywhere
The eight are written to one convention, which is most of what makes them worth installing together. Learn one and the next is already familiar.
anywhen(date) // the string — the bare call is the job
anywhen.parts(date) // the pieces, when you need to style them
anyword.count(text) // the extras hang off the same name
anyword.truncate(text, 20)
anyamount.symbol('USD')
anylong.supported // a flag, same ruleThree rules hold across all of them: one exported name per package; the locale is always an option called locale, taking a tag or a fallback chain; and nothing reads ambient state you did not pass, so the same arguments give the same output on a server and in a browser.
anywhen(date, { locale: 'de-DE' })
anymany(items, { locale: ['xx-Nope', 'de-DE'] }) // fallback chain
anyplural(n, forms, { locale: 'ru' })anylocale is the one exception, and deliberately: it answers questions about a locale rather than formatting in one, so the tag is its argument instead of an option.
Bundle cost
The usual worry about a meta-package: does installing eight ship eight? Through a bundler, no.
The ESM build is a flat list of re-exports and the package sets sideEffects: false, so an import you never use has no reference left to keep it alive and the bundler drops it. Importing anywhen from anyfamily costs exactly what importing it from anywhen costs.
// what the published ESM build is, in full
import { anywhen } from 'anywhen'
import { anyamount } from 'anyamount'
// …six more
export { anywhen, anyamount, /* …six more */ }Two honest caveats, both worth knowing before you rely on it:
require() loads all eight
The CJS build calls require for every package at module scope — that is what CJS is. Nothing is tree-shaken, so on a CJS path requiring the meta for one formatter loads the other seven. Harmless in a server process, wasteful in a bundle: import the package directly, or use the ESM build.
Shaking is per package, not per extra
A package's extras are properties on its one exported function, so importing anyword brings count, truncate and parts along even if you only segment. That is true of the package on its own as well — the meta adds nothing to it, and the packages are small enough that it has never been worth splitting.
None of this touches disk: node_modules holds all eight either way. Tree-shaking is about what reaches the browser.
Which one to install
Three ways in, same code behind all of them.
anyfamily
You want more than two of them, or you do not yet know which. One dependency line, one version to track, and the bundler drops what you never import. The default answer.
The individual packages
You want exactly one or two, and you would rather see them by name in package.json. Identical code and identical bundle — the meta is a re-export, not a wrapper.
anyfamily-react
You are in React and want the locale set once for the whole tree, relative time that refreshes itself, and stable references for the hooks that return objects. It depends on all eight, so it replaces anyfamily rather than joining it.
Switching is a find-and-replace on the import line — the names and signatures are identical either way, and mixing the two is fine as long as the versions agree.
- import { anywhen } from 'anywhen'
- import { anyamount } from 'anyamount'
+ import { anywhen, anyamount } from 'anyfamily'Versioning
The meta carries its own version and depends on the eight by caret range, not by exact pin.
"dependencies": {
"anywhen": "^2.0.1",
"anyamount": "^2.0.1",
…
"anylocale": "^1.0.1"
}So the meta's number does not track the packages' numbers, and it does not need to. A fix or a feature released in anywhen reaches you on your next install without anything happening here — the caret already covers it. The meta is republished for its own reasons: a new export to forward, a new type, a major that moves a range.
Every package in the family is released together through changesets, leaves before metas, so a published meta never points at a version that is not on npm yet.
The one number that is paired: anyfamily and anyfamily-react move together, so the same version of each wraps the same set of packages.
Support flags
Five of the eight rest on Intl APIs that have been everywhere for years. Three are newer and can be missing on an older runtime, so they carry a flag — feature-detect with it rather than with a version table.
import { anylong, anyword, anylocale } from 'anyfamily'
anylong.supported // Intl.DurationFormat
anyword.supported // Intl.Segmenter
anylocale.supported // Intl Locale Info
const elapsed = anylong.supported ? anylong(ms) : `${Math.round(ms / 1000)}s`Where a flag is false, calling that package throws. The other five need no flag and have none — asking for anywhen.supported gets you undefined, not a warning.
Types
Every option and result type from the eight is re-exported, so a typed wrapper needs one import instead of eight.
import type {
Locale,
AnywhenOptions, DateInput, Thresholds,
AnyamountOptions, Unit, SingleUnit,
AnymanyOptions, Sort,
AnyaroundOptions, AnyaroundInfo, Display,
AnylongOptions, DurationInput, DurationRecord,
AnypluralOptions, Forms, PluralCategory,
AnywordOptions, AnywordTruncateOptions, Granularity,
AnylocaleInfo, Direction, Weekday,
} from 'anyfamily'Names that repeat across packages are prefixed here, since they cannot all be Mode. The rule is mechanical — the package name in front, the original after.
Mode -> AnywhenMode, AnyamountMode, AnyaroundMode
Style -> AnywhenStyle, AnyamountStyle, AnyaroundStyle
SmartOptions -> AnyamountSmartOptions, AnyaroundSmartOptions
CurrencyOptions-> AnyamountCurrencyOptions, AnyaroundCurrencyOptionsLocale is exported once, unprefixed: a tag or a fallback chain, structurally identical in all eight.
Limitations
A few things worth knowing before you ship:
It adds no behaviour
Every formatting rule, option and edge case lives in the package the name comes from. When output looks wrong, the answer is in that package's reference — this layer only forwards.
One extra name to keep current
A caret range means core fixes reach you without a meta release, but a brand-new export needs the meta republished before you can import it from here. Reach for the package directly if you need something the day it ships.
Eight packages still land in node_modules
Tree-shaking is about what reaches your bundle, not about what npm installs. On disk the meta costs the same as installing all eight, because that is what it does.
No React here
These are plain functions, safe in a server component, a script or a worker. Hooks, the shared locale provider and the self-ticking relative time live in anyfamily-react.