Skip to content

Pattern: Shared Module Store

Problem

Implement pattern: shared module store in a production-friendly way with @vielzeug/stateit while keeping setup and cleanup explicit.

Runnable Example

The snippet below is copy-paste runnable in a TypeScript project with @vielzeug/stateit installed.

Structure stores as plain modules — no class registration or plugin needed:

ts
// stores/auth.store.ts
import { store, computed, readonly } from '@vielzeug/stateit';

type AuthState = {
  token: string | null;
  user: User | null;
  loading: boolean;
};

const s = store<AuthState>({ token: null, user: null, loading: false });

// Computed signals for derived values
export const isAuthenticated = computed(() => !!s.value.token);
export const currentUser = computed(() => s.value.user);

// Public read-only view — callers can observe but not mutate
export const authStore = readonly(s);

// Mutations (exported as functions, not methods)
export async function login(credentials: Credentials) {
  s.patch({ loading: true });
  try {
    const { token, user } = await authenticate(credentials);
    s.value = { token, user, loading: false };
  } catch {
    s.patch({ loading: false });
  }
}

export function logout() {
  s.reset();
}

Expected Output

  • The example runs without type errors in a standard TypeScript setup.
  • The main flow produces the behavior described in the recipe title.

Common Pitfalls

  • Forgetting cleanup/dispose calls can leak listeners or stale state.
  • Skipping explicit typing can hide integration issues until runtime.
  • Not handling error branches makes examples harder to adapt safely.