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.