mrkeyoor.com_
Sat 08 Aug 21:01 UTC
npmUtilsupdated 08 Aug 2026

@react-dnd/invariant

`@react-dnd/invariant` is the one-function assertion helper used inside React DnD. Call `invariant(condition, message, ...values)` and it returns when the condition is truthy; otherwise it throws an `Error` named `Invariant Violation`, replacing each `%s` in the message with the next value. It has no runtime dependencies and is unrelated to drag-and-drop behavior. Its millions of downloads are mainly a consequence of React DnD depending on it, not evidence that application developers need to install it directly.

Verdict

Do not add this package merely because its download count looks reassuring; it is a React DnD implementation detail with stale published packaging and weak TypeScript semantics. Keep it only where exact React DnD compatibility is the requirement.

API stability4/5There is only one exported function, and its truthy-return, falsy-throw, `%s` replacement, error name, and `framesToPop` behavior are straightforward. That tiny surface is unlikely to surprise existing callers. The score is not perfect because the repository package manifest later moved to dual output and an exports map without a matching npm release, and the runtime's optional-message behavior disagrees with its mandatory TypeScript parameter.
Docs1/5The npm package has no README, its description is the uninformative word `invariantx`, and the linked repository README documents React DnD rather than this helper. The only useful guidance is a source comment above the function, and that comment says production messages will be stripped even though the published implementation still formats them. Consumers must inspect five small tarball files to learn the actual contract.
Maintenance2/5Version 4.0.2 was published on 2022-04-19. The utility directory received packaging commits through 2023-01-20, including a CommonJS build and exports map, but those changes did not reach npm. The broader React DnD repository was pushed on 2025-07-06 and is not archived, yet package-specific release activity has stopped. Stability reduces the need for churn, but unpublished fixes are a concrete maintenance gap.
Ecosystem2/5npm recorded 4,597,824 downloads for 2026-07-31 through 2026-08-06, and React DnD itself is a well-known project with 21,628 GitHub stars. Those numbers mostly reflect transitive use by React DnD packages: repository code search shows the helper imported throughout dnd-core, react-dnd, and touch-backend. There is no plugin ecosystem, package documentation, or meaningful integration surface beyond throwing one Error.

Use it if

  • You contribute to React DnD or maintain code already standardized on its exact Invariant Violation error behavior
  • You need a dependency-free runtime assertion with only `%s` substitution and do not need TypeScript control-flow narrowing
  • You are preserving compatibility with existing tests or error handling that checks the React DnD helper's error name
Skip it if

Setup reality

Installation has no native build, peer dependency, configuration file, or runtime dependency. The sharp edges are all about choosing an internal utility as a direct dependency. Version 4.0.2 is an ESM package whose `main` points to `dist/index.js`; older `require()` test runners and CommonJS applications cannot consume it normally. The React DnD repository later changed this workspace package to emit CommonJS and ESM with an exports map, but npm still serves the April 2022 package, so copying configuration from the current repository describes artifacts users do not receive. There is no package-specific README or documentation site. The message is mandatory in the TypeScript declaration, and it should always be passed at runtime too: in production, `invariant(true, undefined)` throws before it even checks the true condition, while development does not. Only `%s` is interpolated, extra arguments are ignored, and missing arguments become the string `undefined`. Most importantly, the declaration is `(condition: any, format: string, ...args: any[]) => void`, not an assertion signature, so TypeScript will not narrow nullable values after the call. Wrap it in your own typed assertion if compatibility forces you to use it. For new code, `tiny-invariant` or a small local `asserts` function is a cleaner contract and avoids depending on React DnD's private utility release cadence.

Patterns

Assert an internal conditionassert-condition

import { invariant } from '@react-dnd/invariant';

invariant(items.length > 0, 'Expected at least one item');
process(items[0]);

Use this for programmer assumptions, not user-input validation. A false condition throws synchronously with the name Invariant Violation.

Insert a value into the error messageformat-error-value

invariant(
  handlers.has(handlerId),
  'Expected handler %s to be registered',
  handlerId,
);

Only `%s` is supported. Tokens such as `%d`, `%j`, or named placeholders are not interpreted.

Insert multiple values in orderformat-multiple-values

invariant(
  sourceType === targetType,
  'Cannot connect source %s to target %s',
  sourceType,
  targetType,
);

Each `%s` consumes the next argument. Too few values put `undefined` into the message; extra values are ignored.

Add the TypeScript narrowing the package lacksassert-defined-with-types

import { invariant } from '@react-dnd/invariant';

function assertDefined<T>(
  value: T,
  label: string,
): asserts value is NonNullable<T> {
  invariant(value != null, '%s must be defined', label);
}

assertDefined(currentUser, 'currentUser');
console.log(currentUser.id);

The wrapper's `asserts` return type performs narrowing. Calling invariant directly does not narrow because version 4.0.2 declares a void return.

Reject an out-of-range lookupassert-array-member

const item = items[index];
invariant(item !== undefined, 'No item at index %s', index);

// TypeScript may still consider item undefined here.
handle(item!);

The non-null assertion is still needed with strict indexed access. Prefer a local typed assertion wrapper if this pattern occurs often.

Recognize the thrown errorinspect-invariant-error

try {
  invariant(config.ready, 'Configuration is not ready');
} catch (error) {
  if (error instanceof Error && error.name === 'Invariant Violation') {
    reportInternalBug(error);
  } else {
    throw error;
  }
}

The package exports no custom Error class, so checks are string-based. Avoid treating invariant failures as recoverable validation errors.

Test the failure messagetest-invariant-failure

import { expect, it } from 'vitest';

it('rejects an unknown type', () => {
  expect(() => invariant(false, 'Unknown type %s', 'ghost'))
    .toThrow('Unknown type ghost');
});

The error is thrown synchronously. Also assert the name separately if callers depend on Invariant Violation.

Keep a message on every assertionrequire-message-always

// Safe in development and production:
invariant(connection !== null, 'Expected an active connection');

Never bypass the types to omit the message. In production the implementation throws about the missing message even when the condition is true.

Alternatives

PackageRegistryPick it when
tiny-invariantnpmChoose it for a deliberately public small invariant helper with clearer direct-use documentation
invariantnpmChoose it when compatibility with the long-established Facebook-style invariant package matters
ts-invariantnpmChoose it for an invariant API maintained as a standalone TypeScript-oriented package
zodnpmChoose it when the real job is validating unknown external data and returning structured, typed errors