Types: `ToastTransitionProps.position` is `ToastPosition | string` — should be `ToastPosition` (only the 6 positions have CSS)
Describe the bug
ToastTransitionProps.position is typed ToastPosition | string, but every other place that describes
the same value uses the pure union ToastPosition, and the runtime only supports the six known positions.
The | string widens the union to plain string (TypeScript subsumes 'top-right' | … | string into
string), so consumers of ToastTransitionProps — i.e. anyone writing a custom transition — lose all
type-safety and autocomplete on position, and the compiler will happily accept an invalid value that
produces no animation at runtime.
Version
Evidence
dist/index.d.ts (built types):
// line 99 — the public option
interface CommonOptions { position?: ToastPosition; ... }
// line 294 — internal toast props
interface ToastProps extends ToastOptions { position: ToastPosition; ... }
// line 278 — the outlier
interface ToastTransitionProps { position: ToastPosition | string; ... } // ⟵ should be ToastPositionToastPosition is the closed union:
type ToastPosition = 'top-right' | 'top-center' | 'top-left'
| 'bottom-right' | 'bottom-center' | 'bottom-left';Why | string is incorrect (not just imprecise):
- The transition builds its animation class by concatenation —
const enterClassName = appendPosition ? \${enter}--${position}` : enter— and the shipped CSS only defines rules for the six known positions (.Toastify__bounce-enter--top-left,--top-right,--top-center,--bottom-left,--bottom-right,--bottom-center). Any other string yields a class likeToastify__bounce-enter--whatever` that matches no rule → no animation (silent breakage). - The only value ever passed to a transition's
positionoriginates from the container/toast options, which are typedToastPosition(CommonOptions.position?: ToastPosition). So the| stringarm is never legitimately reachable through normal use.
Expected behavior
interface ToastTransitionProps {
position: ToastPosition; // closed union, consistent with CommonOptions / ToastProps
}This restores typo-safety and autocomplete for custom-transition authors and matches what the runtime actually supports. (If arbitrary positions are intended to be supported in future, the fix would instead be to add the corresponding CSS — but as shipped, the types are looser than the implementation.)
How I found this
While generating ReScript type bindings from react-toastify's .d.ts, the binding for <Bounce> came out
as position: string (correct per the types) while <ToastContainer> came out as a proper 6-value enum —
the asymmetry traced back to this single | string. Filing since it looks like an unintended widening.
Source: fkhadra/react-toastify