npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@leancodepl/utils

v10.1.3

Published

Common utility functions and React hooks for web applications

Downloads

1,804

Readme

@leancodepl/utils

A TypeScript utility library for common development tasks including assertions, object transformations, file operations, and hooks.

Installation

npm install @leancodepl/utils
# or
yarn add @leancodepl/utils

API

assertDefined(value, message)

Asserts that a value is not undefined. Throws an error if the value is undefined.

Parameters:

  • value: T | undefined - The value to check for undefined
  • message?: string - Optional error message to use if assertion fails

Usage:

import { assertDefined } from "@leancodepl/utils"

interface User {
  name: string
  email: string
}

function processUserAssert(user?: User) {
  assertDefined(user) // Throws if undefined, no return value
  return user.name // TypeScript knows user is defined
}

assertNotNull(value, message)

Asserts that a value is not null. Throws an error if the value is null.

Parameters:

  • value: T | null - The value to check for null
  • message?: string - Optional error message to use if assertion fails

Usage:

import { assertNotNull } from "@leancodepl/utils"

interface User {
  name: string
  email: string
}

function processData(data: string | null) {
  assertNotNull(data, "Data cannot be null")
  return data.toUpperCase() // TypeScript knows data is string
}

assertNotEmpty(value, message)

Asserts that a value is not null or undefined. Throws an error if the value is null or undefined.

Parameters:

  • value: T | null | undefined - The value to check for null or undefined
  • message?: string - Optional error message to use if assertion fails

Usage:

import { assertNotEmpty } from "@leancodepl/utils"

interface User {
  name: string
  email: string
}

function processValue(value: string | null | undefined) {
  assertNotEmpty(value, "Value is required")
  return value.length // TypeScript knows value is string
}

ensureDefined(value, message)

Ensures that a value is defined, returning it if defined or throwing an error if undefined.

Parameters:

  • value: T | undefined - The value to ensure is defined
  • message?: string - Optional error message to use if the value is undefined

Returns: The value if it is defined

Usage:

import { ensureDefined } from "@leancodepl/utils"

interface User {
  name: string
  email: string
}

function processUser(user?: User) {
  const definedUser = ensureDefined(user) // Returns User or throws
  return definedUser.name
}

ensureNotNull(value, message)

Ensures that a value is not null, returning it if not null or throwing an error if null.

Parameters:

  • value: T | null - The value to ensure is not null
  • message?: string - Optional error message to use if the value is null

Returns: The value if it is not null

Usage:

import { ensureNotNull } from "@leancodepl/utils"

interface User {
  name: string
  email: string
}

function processData(data: string | null) {
  const validData = ensureNotNull(data, "Data cannot be null")
  return validData.toUpperCase()
}

ensureNotEmpty(value, message)

Ensures that a value is not null or undefined, returning it if valid or throwing an error if empty.

Parameters:

  • value: T | null | undefined - The value to ensure is not null or undefined
  • message?: string - Optional error message to use if the value is null or undefined

Returns: The value if it is not null or undefined

Usage:

import { ensureNotEmpty } from "@leancodepl/utils"

interface User {
  name: string
  email: string
}

function processValue(value: string | null | undefined) {
  const validValue = ensureNotEmpty(value, "Value is required")
  return validValue.length
}

addPrefix(object, prefix)

Adds a prefix to all keys in an object, creating a new object with prefixed keys.

Parameters:

  • object: T extends object - The object whose keys will be prefixed
  • prefix: TPrefix extends string - The prefix string to add to each key

Returns: A new object with all keys prefixed

Usage:

import { addPrefix } from "@leancodepl/utils"

const apiData = { userId: 1, userName: "John" }
const prefixed = addPrefix(apiData, "api_")
// Result: { api_userId: 1, api_userName: 'John' }

capitalizeDeep(value)

Recursively transforms all object keys to use capitalized (PascalCase) format.

Parameters:

  • value: T - The value to transform (can be object, array, or primitive)

Returns: A new object with all keys converted to PascalCase

Usage:

import { capitalizeDeep } from "@leancodepl/utils"

const clientData = { userId: 1, userName: "John", profile: { firstName: "John" } }
const serverData = capitalizeDeep(clientData)
// Result: { UserId: 1, UserName: 'John', Profile: { FirstName: 'John' } }

uncapitalizeDeep(value)

Recursively transforms all object keys to use uncapitalized (camelCase) format.

Parameters:

  • value: T - The value to transform (can be object, array, or primitive)

Returns: A new object with all keys converted to camelCase

Usage:

import { uncapitalizeDeep } from "@leancodepl/utils"

const serverData = { UserId: 1, UserName: "John", Profile: { FirstName: "John" } }
const clientData = uncapitalizeDeep(serverData)
// Result: { userId: 1, userName: 'John', profile: { firstName: 'John' } }

toLowerFirst(value)

Converts the first character of a string to lowercase.

Parameters:

  • value: string - The string to transform

Returns: The string with the first character in lowercase

Usage:

import { toLowerFirst } from "@leancodepl/utils"

const result = toLowerFirst("HelloWorld")
// Result: 'helloWorld'

toUpperFirst(value)

Converts the first character of a string to uppercase.

Parameters:

  • value: string - The string to transform

Returns: The string with the first character in uppercase

Usage:

import { toUpperFirst } from "@leancodepl/utils"

const result = toUpperFirst("helloWorld")
// Result: 'HelloWorld'

downloadFile(dataOrUrl, options)

Download a file from URL or Blob object.

Parameters:

  • url: string OR obj: Blob | MediaSource - The URL to download from or the Blob/MediaSource object
  • options?: DownloadFileOptions - Optional download options

Usage:

import { downloadFile } from "@leancodepl/utils"

// Download from URL
downloadFile("https://example.com/file.pdf", { name: "document.pdf" })

// Download from Blob
const blob = new Blob(["Hello World"], { type: "text/plain" })
downloadFile(blob, { name: "hello.txt" })

useDialog(onAfterClose)

React hook for managing dialog state with optional callback after closing. Provides convenient open/close functions and tracks the dialog's open state.

Parameters:

  • onAfterClose?: () => void - Optional callback function to execute after the dialog closes

Returns: Object containing { isDialogOpen: boolean, openDialog: () => void, closeDialog: () => void }

Usage:

import React from 'react';
import { useDialog } from '@leancodepl/utils';

function MyComponent() {
  const { isDialogOpen, openDialog, closeDialog } = useDialog(() => {
    console.log('Dialog closed');
  });

  return (
    <div>
      <button onClick={openDialog}>Open Dialog</button>
      {isDialogOpen && (
        <div className="dialog">
          <p>Dialog content</p>
          <button onClick={closeDialog}>Close</button>
        </div>
      )}
    </div>
  );
}

useRunInTask()

React hook for tracking async task execution with loading state. Automatically manages a loading counter and provides a wrapper function for tasks.

Returns: A tuple containing [isLoading: boolean, runInTask: function]

Usage:

import React from 'react';
import { useRunInTask } from '@leancodepl/utils';

async function saveData() {
  console.log('Saving data...');
}

function MyComponent() {
  const [isLoading, runInTask] = useRunInTask();

  const handleSave = async () => {
    await runInTask(async () => {
      await saveData();
    });
  };

  return (
    <button onClick={handleSave} disabled={isLoading}>
      {isLoading ? 'Saving...' : 'Save'}
    </button>
  );
}

useBoundRunInTask(block)

React hook for bound task execution with loading state. Creates a wrapped version of a function that automatically tracks loading state.

Parameters:

  • block: T | undefined - The function to wrap with task tracking

Returns: A tuple containing [isLoading: boolean, wrappedFunction: T]

Usage:

import React, { useState, useEffect } from 'react';
import { useBoundRunInTask } from '@leancodepl/utils';

interface User {
  name: string;
  email: string;
}

async function fetchUser(userId: string): Promise<User> {
  return { name: 'John Doe', email: '[email protected]' };
}

function UserProfile({ userId }: { userId: string }) {
  const [user, setUser] = useState<User | null>(null);

  const [isLoading, loadUser] = useBoundRunInTask(async () => {
    const userData = await fetchUser(userId);
    setUser(userData);
  });

  useEffect(() => {
    loadUser();
  }, [userId, loadUser]);

  if (isLoading) return <div>Loading...</div>;
  return <div>{user?.name}</div>;
}

useKeyByRoute(routeMatches)

React hook for generating keys based on current route matches.

Parameters:

  • routeMatches: Record<TKey, (object | null)[] | never | object | null> - Record of route keys to match objects or arrays

Returns: Array of active route keys

Usage:

import { useKeyByRoute } from '@leancodepl/utils';

function MyComponent() {
  const routeKeys = useKeyByRoute({
    home: { path: '/' },
    profile: { path: '/profile' },
    settings: null
  });

  return (
    <div>
      Active routes: {routeKeys.join(', ')}
    </div>
  );
}

useSetUnset(set)

React hook for boolean state management helpers.

Parameters:

  • set: Dispatch<SetStateAction<boolean>> - The state setter function from useState

Returns: A tuple containing [setTrue: function, setFalse: function]

Usage:

import React, { useState } from 'react';
import { useSetUnset } from '@leancodepl/utils';

function MyComponent() {
  const [isVisible, setIsVisible] = useState(false);
  const [show, hide] = useSetUnset(setIsVisible);

  return (
    <div>
      <button onClick={show}>Show</button>
      <button onClick={hide}>Hide</button>
      {isVisible && <div>Visible content</div>}
    </div>
  );
}

useSyncState(state, onChange, compare)

Synchronizes external state changes with a callback function, calling the callback only when state actually changes.

Parameters:

  • state: T - The current state value to monitor for changes
  • onChange: (state: T) => void - Callback function executed when state changes
  • compare?: (a: T, b: T) => boolean - Optional comparison function to determine if state has changed (defaults to strict equality)

Usage:

import { useSyncState } from "@leancodepl/utils";

function MyComponent({ externalValue }: { externalValue: string }) {
  useSyncState(externalValue, (newValue) => {
    console.log('Value changed to:', newValue);
  });

  return <div>{externalValue}</div>;
}

mkValueContext()

Creates a React context hook for managing optional state values with Provider and setter utilities. Returns a hook with attached Provider component and set function for declarative value management.

Returns: Hook function with attached Provider component and set function

Usage:

import { mkValueContext } from "@leancodepl/utils";

const useTheme = mkValueContext<string>();

function App() {
  return (
    <useTheme.Provider initialValue="dark">
      <ThemeConsumer />
    </useTheme.Provider>
  );
}

function ThemeConsumer() {
  const [theme] = useTheme();
  return <div>Current theme: {theme}</div>;
}

Using set to declaratively set context value:

import { mkValueContext } from "@leancodepl/utils";

const useActiveUser = mkValueContext<string>();

function UserProfile({ userId }: { userId: string }) {
  useActiveUser.set(userId); // Sets value on mount, clears on unmount
  return <div>Profile content</div>;
}

function UserBadge() {
  const [activeUserId] = useActiveUser();
  return <div>Active user: {activeUserId}</div>;
}