mrkeyoor.com_
Wed 23 Sept 12:34 UTC
npmUtilsupdated 23 Sept 2026

@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.

Verdict

@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

Lab card: what happened when we installed @schummar/icu-type-parserScreenshot of @schummar/icu-type-parser documentation
Install✓ · 1.6s1 package on disk · 1 MB
ImportESM import fails · require() fails · ESM package with exports map
Browsern/acould not be bundled for the browser (Node-only code, most likely)
TypesTypeScript types bundled
Known vulns00 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.

API stability4/5@schummar/icu-type-parser 1.26.1 exports exactly 2 public types, `GetICUArgs` and `GetICUArgsOptions`. A tarball comparison with 1.25.2 shows the declaration file is byte-for-byte unchanged; only the version and release script metadata differ. The package is past 1.0 and has no runtime surface to break. Assignment compatibility can still change when its conditional-type recursion, select-branch merging, escape handling, or option defaults change, so type tests belong in consuming libraries.
Docs1/5The npm tarball contains 0 README files and the linked repository page teaches the parent `schummar-translate` product. Package metadata calls this a TypeScript ICU parser but does not say that runtime resolution fails or that `dist/index.js` is empty. The declaration comments describe the final computed type and some internal helpers. Users still have to inspect about 60 lines of dense conditional types to discover literal widening, default `unknown` values, `ProvidedArgs`, select unions, and apostrophe escape behavior.
Maintenance4/5npm published 1.26.1 on February 11, 2026, and GitHub reports a monorepo push on August 8, 2026. The repository is not archived, has 136 stars, and shows 2 open issues and pull requests across the parent project. The package first appeared in November 2024 and has moved with the parent release train. Its latest version changed release plumbing rather than parser logic, and there is no package-specific changelog or dedicated documentation to make maintenance scope obvious.
Ecosystem3/5The npm endpoint counted 4,699,459 downloads from August 18 through 24, 2026. The package adds 0 runtime dependencies and disappears from compiled JavaScript when imported correctly, which makes it cheap for typed translation libraries to reuse. Its visible standalone community is much smaller: 136 stars belong to the entire schummar-translate repository, and there are no adapters to runtime ICU engines. Consumers must pair it manually with a formatter and keep compile-time assumptions aligned with runtime syntax.

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`.
Skip it if

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-parser

Version 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

PackageRegistryPick it when
@formatjs/icu-messageformat-parsernpmUse it when runtime ICU parsing, syntax errors, source locations, or an abstract syntax tree is required.
intl-messageformatnpmUse it when the application must compile and render ICU messages with locale-aware values.
schummar-translatenpmUse the parent library when typed dictionaries also need loading, caching, React integration, and runtime translation.
typesafe-i18nnpmUse 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.