@schummar/icu-type-parser review
@schummar/icu-type-parser 1.26.1 is a declaration-only TypeScript parser for ICU message literals. `GetICUArgs<'Hello {name}'>` computes a required `name` property at compile time; options can assign value types for plain, numeric, plural, date, time, and select arguments or mark wrapper-provided names optional. No JavaScript parser or formatter runs in the application. The tarball contains an empty `dist/index.js`, and its export map exposes only a TypeScript `types` condition. Compared with 1.25.2, version 1.26.1 changes only package metadata by removing the old release script; the declaration file is identical.
@schummar/icu-type-parser 1.26.1 installed as 1 package in 1.6 seconds, but both runtime imports failed on Node.js 22.23.2 in our sandbox because the published entry is types-only. Install it as a dev dependency for literal ICU inference; use a real parser or formatter for any runtime job.
We installed it
| Install | ✓ · 1.6s | 1 package on disk · 1 MB |
| Import | ✗ | ESM import fails · require() fails · ESM package with exports map |
| Browser | n/a | could not be bundled for the browser (Node-only code, most likely) |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does @schummar/icu-type-parser install cleanly?
Yes. In a fresh container with an empty cache, npm install @schummar/icu-type-parser finished in 2 seconds, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.
Can @schummar/icu-type-parser run in a browser?
Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.
Does @schummar/icu-type-parser work with both ESM and CommonJS?
Neither plain import nor require succeeded in our sandbox, so it needs a bundler or extra setup.
Does @schummar/icu-type-parser include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
@schummar/icu-type-parser or @formatjs/icu-messageformat-parser: which should you use?
@formatjs/icu-messageformat-parser: Use it when runtime ICU parsing, syntax errors, source locations, or an abstract syntax tree is required. @schummar/icu-type-parser 1.26.1 installed as 1 package in 1.6 seconds, but both runtime imports failed on Node.js 22.23.2 in our sandbox because the published entry is types-only.
When should you not use @schummar/icu-type-parser?
Any code needs runtime parsing, validation, or formatting. The package's JavaScript file is empty and both runtime import styles failed in our Node 22.23.2 sandbox.
Use it if
- ICU messages remain TypeScript literals and missing interpolation arguments should fail during type checking.
- A translation wrapper needs to infer a values object from every `as const` dictionary entry.
- Your application wants its own string, number, and date value types attached to ICU format categories.
- Locale, tenant, or another wrapper-supplied argument should become optional for downstream callers through `ProvidedArgs`.
- Any code needs runtime parsing, validation, or formatting. The package's JavaScript file is empty and both runtime import styles failed in our Node 22.23.2 sandbox.
- Messages arrive from JSON, a database, or an API as plain `string`. Template-literal inference needs exact literal characters, usually preserved with `as const`.
- A standalone user guide is required. The tarball has no README, and the repository README documents `schummar-translate` rather than this package's 2 exported types.
- You need an ICU abstract syntax tree, source locations, or syntax errors. Recursive conditional types compute argument shapes but produce no runtime parse result.
- TypeScript compilation is already strained by a large catalog. Every instantiated message is processed through recursive template-literal types, so measure your own checker before adopting it widely.
Setup reality
Our fresh Node 22 install of @schummar/icu-type-parser 1.26.1 finished in 1.6 seconds. It left 1 package and 1 MB on disk; the package itself was 24 KB unpacked. npm audit found 0 known vulnerabilities. The ESM manifest has 0 direct dependencies, 0 peers, an MIT license, an exports map, and bundled TypeScript declarations. Runtime require() and ESM import both failed under Node.js 22.23.2 in our sandbox. esbuild also could not make a browser bundle.
Those failures match a type-only package whose export map contains just types. Install it as a development dependency and write import type {GetICUArgs, GetICUArgsOptions} from '@schummar/icu-type-parser'. TypeScript erases that import, so deployed JavaScript should contain no reference to the package. The tarball's dist/index.js is empty and not reachable through a runtime export condition. Version 1.26.1 does not alter the declaration logic from 1.25.2; it only removes a package release script.
Literal preservation decides whether the parser is useful. A dictionary written as const retains braces and format tokens for the compiler to inspect. A variable widened to string loses that structure. Default option properties resolve to unknown, so supply ICUArgument, ICUNumberArgument, and ICUDateArgument types when value checking matters. Number, plural, and selectordinal share the numeric option; date and time share the date option. ProvidedArgs names properties that the computed result makes optional.
This is inference, not ICU conformance checking. The declarations recursively find brace blocks, trim whitespace, handle selected apostrophe escapes, and merge select branches. An other branch deliberately permits arbitrary selector strings, while branch-specific nested placeholders can form a union. No locale data, plural rules, message rendering, or runtime error reporting exists. Pair the type with an ICU formatter such as intl-messageformat, keep the format and type source in sync, and benchmark tsc on a representative catalog before applying it everywhere.
Patterns
Keep the parser out of runtime dependencies install-type-dependency
npm install --save-dev @schummar/icu-type-parserVersion 1.26.1 has an empty JavaScript file and only a `types` export condition, so application code should import it as types only.
Compute one required argument infer-placeholder
import type {GetICUArgs} from '@schummar/icu-type-parser';
type WelcomeArgs = GetICUArgs<'Hello, {name}!'>;
const values: WelcomeArgs = {name: 'Ada'};The `name` key is required, but its value is `unknown` until an `ICUArgument` option supplies an application type.
Set the three ICU value families define-value-options
import type {GetICUArgsOptions} from '@schummar/icu-type-parser';
interface AppICUOptions extends GetICUArgsOptions {
ICUArgument: string;
ICUNumberArgument: number;
ICUDateArgument: Date | number;
}Plain placeholders use `ICUArgument`; number, plural, and selectordinal use the numeric type; date and time use the date type.
Require a numeric formatted value type-number-format
type PriceArgs = GetICUArgs<
'Total: {amount, number}',
{ICUNumberArgument: number}
>;
const values: PriceArgs = {amount: 19.95};The computed `amount` property is `number`; the package does not format 19.95 or choose currency options at runtime.
Share one type across date and time type-date-and-time
type EventArgs = GetICUArgs<
'Starts {when, date, short} at {when, time, short}',
{ICUDateArgument: Date | number}
>;
const values: EventArgs = {when: new Date()};Both occurrences merge into 1 `when` property because `date` and `time` read `ICUDateArgument`.
Infer the selector for a plural type-plural-count
type CountArgs = GetICUArgs<
'{count, plural, =0 {No files} one {One file} other {# files}}',
{ICUNumberArgument: number}
>;
const values: CountArgs = {count: 3};Plural and selectordinal selectors use `ICUNumberArgument`; plural-category choice still belongs to the runtime formatter.
Restrict a select without other type-select-options
type DensityArgs = GetICUArgs<
'{density, select, compact {Small} full {Large}}'
>;
const compact: DensityArgs = {density: 'compact'};
const full: DensityArgs = {density: 'full'};With 2 named branches and no `other`, the selector is limited to `compact | full`.
Permit future values through other allow-select-fallback
type StateArgs = GetICUArgs<
'{state, select, ready {Ready} other {Unknown}}'
>;
const known: StateArgs = {state: 'ready'};
const future: StateArgs = {state: 'queued'};An `other` branch widens the selector so an arbitrary string such as `queued` remains assignable.
Collect values nested inside select branches infer-branch-placeholders
type GreetingArgs = GetICUArgs<
'{role, select, admin {Hello {adminName}} member {Hello {memberName}}}',
{ICUArgument: string}
>;
const admin: GreetingArgs = {role: 'admin', adminName: 'Ada'};
const member: GreetingArgs = {role: 'member', memberName: 'Lin'};The 2 branches form a union whose selector can carry the placeholder required by that branch.
Merge arguments from several literals combine-message-tuple
const messages = [
'Hello {name}',
'You have {count, number} alerts',
] as const;
type PageArgs = GetICUArgs<
typeof messages,
{ICUArgument: string; ICUNumberArgument: number}
>;
const values: PageArgs = {name: 'Ada', count: 2};`as const` preserves 2 literal strings; a `string[]` annotation would discard the characters the type parser needs.
Make a wrapper-owned value optional mark-provided-argument
type RequestArgs = GetICUArgs<
'Hello {name} from {tenant}',
{ICUArgument: string; ProvidedArgs: 'tenant'}
>;
const callerValues: RequestArgs = {name: 'Ada'};`ProvidedArgs: 'tenant'` only changes the computed property to optional; the runtime wrapper still has to supply the tenant value.
Preserve an apostrophe-escaped brace ignore-escaped-placeholder
type HelpArgs = GetICUArgs<
"Write '{name}' literally, then greet {user}",
{ICUArgument: string}
>;
const values: HelpArgs = {user: 'Ada'};The selected ICU apostrophe escape removes `{name}` from inference, leaving 1 required property named `user`.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| @formatjs/icu-messageformat-parser | npm | Use it when runtime ICU parsing, syntax errors, source locations, or an abstract syntax tree is required. |
| intl-messageformat | npm | Use it when the application must compile and render ICU messages with locale-aware values. |
| schummar-translate | npm | Use the parent library when typed dictionaries also need loading, caching, React integration, and runtime translation. |
| typesafe-i18n | npm | Use it when a generated end-to-end typed localization workflow fits better than one ICU argument utility. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

