Yevhen Klymentiev
dark
light
console
darkness
y.klymentiev@gmail.com
Reusable Snippets|Practical utility code for everyday use — custom-built and ready to share

once

Ensures a function is only called once. Provides a .reset() method to allow re-invocation.

TypeScript
Copied!
1/**
2 * Ensures a function is only called once.
3 * Provides a `.reset()` method to allow re-invocation.
4 *
5 * @param fn - The function to wrap.
6 * @returns A function that can only be called once, with `.reset()` method.
7 */
8export function once<T extends (...args: any[]) => any>(
9  fn: T
10): ((...args: Parameters<T>) => ReturnType<T>) & { reset: () => void } {
11  let called = false;
12  let result: ReturnType<T>;
13
14  const wrapper = (...args: Parameters<T>) => {
15    if (!called) {
16      result = fn(...args);
17      called = true;
18    }
19    return result;
20  };
21
22  wrapper.reset = () => {
23    called = false;
24    result = undefined as any;
25  };
26
27  return wrapper;
28}
  • Ensures Single Execution

    Guarantees that the wrapped function runs only once, making it ideal for one-time initialization logic.

  • Result Memoization

    Returns the cached result on subsequent calls, preserving consistent output without recomputation.

  • Reset Capability

    Includes a .reset() method to explicitly allow the function to run again, offering manual control over reuse.

  • Type-Safe and Generalized

    Preserves argument and return types through TypeScript generics, making it safe for a variety of function signatures.

  • Lightweight and Side-Effect-Free

    Cleanly separates function invocation logic without modifying the original function itself.

Tests | Examples

TypeScript
Copied!
1test('once - only calls function once', () => {
2  const fn = jest.fn((x: number) => x * 2);
3  const wrapped = once(fn);
4
5  expect(wrapped(2)).toBe(4);
6  expect(wrapped(3)).toBe(4); // returns first result
7  expect(wrapped(10)).toBe(4);
8  expect(fn).toHaveBeenCalledTimes(1);
9});
10
11test('once - no arguments', () => {
12  const fn = jest.fn(() => 'ran');
13  const wrapped = once(fn);
14
15  expect(wrapped()).toBe('ran');
16  expect(wrapped()).toBe('ran');
17  expect(fn).toHaveBeenCalledTimes(1);
18});
19
20test('once - reset allows re-invocation', () => {
21  const fn = jest.fn((x: number) => x + 1);
22  const wrapped = once(fn);
23
24  expect(wrapped(1)).toBe(2);
25  expect(wrapped(2)).toBe(2);
26  expect(fn).toHaveBeenCalledTimes(1);
27
28  wrapped.reset();
29
30  expect(wrapped(5)).toBe(6);
31  expect(fn).toHaveBeenCalledTimes(2);
32});

Common Use Cases

  • Initialization Logic

    Ensure startup code (e.g., setting up listeners, opening connections) runs only once, even if invoked multiple times.

  • Lazy Loading or Memoization

    Run heavy computations or resource-loading code just once per lifecycle or session.

  • Single-Use API Calls

    Prevent duplicate submissions of forms or repeated triggering of critical actions (e.g., payment processing).

  • Testing and Setup Scripts

    Guarantee setup or teardown functions only run once per test suite or script run.

  • Lifecycle Management in UI

    Execute logic like animation setup, component hydration, or event binding a single time with the option to reset later.

Codebase: Utilities -> Functions -> once | Yevhen Klymentiev