Skip to content

TypeScript

Where the types come from, which ones exist, and the two that need narrowing.

@wajub/js ships its own definitions. There is no @types/ package to install and nothing to configure. Every framework wrapper re-exports the same types, so installing one of them is enough.

npm install @wajub/js

The package declares three entry points, each with its own definitions.

ImportDefinitionsSide effect
@wajub/jsdist/index.d.tsFetches the runtime on import
@wajub/js/puredist/pure.d.tsNone until you call loadWajub()
https://js.wajub.comNone, globals onlyThe whole runtime

Everything worth importing

Config and instances
import type {
  EmbeddedConfig,
  PopupConfig,
  CheckoutInstance,
  PopupInstance,
  ComponentConfig,
  ComponentInstance,
  ComponentsFactory,
  ComponentType,
  ConfirmPaymentOptions,
} from '@wajub/js';
Styling, payloads and errors
import type {
  AppearanceConfig,
  AppearanceVariables,
  AppearanceRules,
  AppearanceThemePreset,
  AppearanceColorScheme,
  AppearanceLabels,
  CheckoutLayout,
  CheckoutState,
  EmbedBreakdown,
  SessionPreview,
  ComponentChangeEvent,
  ComponentAddressValue,
  AddressValue,
  AddressMode,
  PhoneFieldMode,
  WajubError,
  WajubErrorType,
} from '@wajub/js';
The runtime and the client
import type {
  WajubRuntime,
  WajubSDK,
  WajubClient,
  WajubFactory,
  WajubInitOptions,
  LoadWajubOptions,
  CreatePaymentParams,
  CreatePaymentResult,
  InitCheckoutOptions,
  InitCheckoutResult,
} from '@wajub/js';

Two more exist for compatibility: EmbedTheme, the deprecated theme shape, and WajubErrorShape, the plain object behind a WajubError.

Two places where narrowing matters

The helpers can return null. Everything imported from @wajub/js resolves to null when there is no window, which is what makes a server render safe. TypeScript will make you handle it.

Nothing throws on the server
import { loadWajub } from '@wajub/js/pure';

const runtime = await loadWajub();
if (!runtime) return;

const checkout = runtime.wajub.mount('#checkout', { sessionId });

Once you hold the runtime, its methods are synchronous and never return null, so this is the only check you need.

The error callbacks are not typed as WajubError. They receive WajubError | Record<string, unknown>, because an error can also arrive as a raw payload from the iframe. Narrow before reading code.

Narrowing an error
import { WajubError } from '@wajub/js';

await mount('#checkout', {
  sessionId,
  onError: (error) => {
    if (error instanceof WajubError) {
      report(error.code, error.retryable);
      return;
    }
    report('unknown_error', false);
  },
});

WajubError is exported as a value, not only a type, so instanceof works. Everything else on this page is a type only import.

Server rendering

The three framework packages already handle the browser check for you, through WajubProvider. Reach for the code below only when you wire @wajub/js yourself.

React, without the wrapper
'use client';

import { useEffect, useRef } from 'react';
import { loadWajub } from '@wajub/js/pure';
import type { CheckoutInstance } from '@wajub/js';

export function Checkout({ sessionId }: { sessionId: string }) {
  const host = useRef<HTMLDivElement>(null);
  const instance = useRef<CheckoutInstance | null>(null);

  useEffect(() => {
    loadWajub().then((runtime) => {
      if (!runtime || !host.current) return;
      instance.current = runtime.wajub.mount(host.current, { sessionId });
    });

    return () => instance.current?.destroy();
  }, [sessionId]);

  return <div ref={host} />;
}

Importing from /pure is what keeps the module free of side effects, so the bundler does not pull a CDN fetch into your server build.

Typing the CDN globals

With the script tag and no npm package, wajub, Wajub and WajubError sit on window. The package declares them globally, so installing it as a development dependency types a project that never bundles it.

Already declared for you
declare global {
  interface Window {
    wajub: WajubSDK;
    Wajub: WajubFactory;
    WajubError: typeof WajubError;
  }
}

Framework types

React and Vue export their own prop types alongside everything above.

PackageAdds
@wajub/reactWajubProviderProps, CheckoutEmbedProps, ComponentEmbedProps, WajubContextValue
@wajub/vueThe same four, plus WAJUB_INJECTION_KEY
@wajub/svelteWajubContextValue only

The Svelte components are not typed

Every component in @wajub/svelte is declared as a bare SvelteComponent, and the package exports no prop types. Your editor will not complete a prop and svelte-check will not catch a misspelled one. Details and the workaround are on Svelte.

What did you think of this content?