Breaking API Changes

TypeScript 5.4 required

Update TypeScript to 5.4 or newer. The declarations now use NoInfer for opt-in typed message contracts. This compiler requirement also applies to projects that use untyped messages; JavaScript runtime behavior is unchanged.

Message formatter generic arguments changed

formatMessage<Values, RichOutput> and $t<Values, RichOutput> now take the ICU argument contract first. Rich output moves to the optional second generic, which defaults to React.ReactNode in React Intl.

// Before: first generic described rich output.
intl.$t<React.ReactNode>(descriptor, values)

// After: first generic describes ICU arguments.
intl.$t<{name: MessageValue}, React.ReactNode>(descriptor, values)

Import MessageValue from react-intl for unformatted placeholders and MessageTag for tag callbacks.

Calls without generics need no migration. With a plain descriptor, both intl.$t(descriptor, values) and intl.formatMessage(descriptor, values) remain permissive: required argument names and types are not inferred from message literals. A descriptor from a typed helper still enforces its contract without call-site generics. Runtime formatting and error handling are unchanged.

Rich output defaults to React.ReactNode in React Intl. In @formatjs/intl, it uses the type supplied to createIntl<T>() (string by default); untyped rich calls use that base type rather than inferring a narrower output type.

See React Intl argument types and core Intl argument types for examples.