@leancodepl/utils
Version:
Common utility functions and React hooks for web applications
466 lines (313 loc) • 10.7 kB
Markdown
# @leancodepl/utils
A TypeScript utility library for common development tasks including assertions, object transformations, file operations,
and hooks.
## Installation
```bash
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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: 'john@example.com' };
}
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:**
```typescript
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:**
```typescript
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>
);
}
```