@ffsm/nullish v0.0.3
Utilities Nullish
A lightweight utility package for handling null and undefined values in TypeScript.
Installation
npm i @ffsm/nullish
OR
yarn add @ffsm/nullish
Usage
import { isNullish } from '@ffsm/nullish';
isNullish(null);
OR
import Nullish from '@ffsm/nullish';
Nullish.isNullish(null);
isNull
Check if a value is specifically null.
import { isNull } from '@ffsm/nullish';
// Example usage
const value = getSomeValue();
if (isNull(value)) {
console.log('Value is null');
}
isUndefined
Check if a value is specifically undefined.
import { isUndefined } from '@ffsm/nullish';
// Example usage
const value = getSomeValue();
if (isUndefined(value)) {
console.log('Value is undefined');
}
isNullish
Check if a value is null or undefined.
import { isNullish } from '@ffsm/nullish';
// Example usage
const value = getSomeValue();
if (isNullish(value)) {
console.log('Value is null or undefined');
} else {
console.log('Value has actual content');
}
isNotNullish
Type guard to check if a value is neither null nor undefined.
import { isNotNullish } from '@ffsm/nullish';
// In conditional statements
if (isNotNullish(user)) {
// TypeScript knows user is not null or undefined here
console.log(user.name);
}
// In array filtering
const validItems = items.filter(isNotNullish);
nullish
Provide a default value for null or undefined values.
import { nullish } from '@ffsm/nullish';
// Basic example with explicit return type
const name = nullish<string>(user.name, 'Anonymous User');
// Use with data processing pipelines
const processedData = pipe(
getData(),
(data) => nullish<any[]>(data, []),
(array) => array.map((item) => nullish<number>(item.value, 0))
);
// Use with configuration objects
const config = {
timeout: nullish<number>(userConfig.timeout, 1000),
retries: nullish<number>(userConfig.retries, 3),
baseUrl: nullish<string>(userConfig.baseUrl, 'https://api.example.com'),
};
chain
Chain multiple functions together, applying each one to the result of the previous function only if the value is not nullish.
import { chain } from '@ffsm/nullish';
// Transform a string through multiple operations
const result = chain(
'hello world',
(str) => str.toUpperCase(),
(str) => str.replace('WORLD', 'TYPESCRIPT')
);
// result: "HELLO TYPESCRIPT"
// Will skip operations if value is nullish
const nullResult = chain(null, (str) => str.toUpperCase());
// nullResult: null
map
Map a value through a series of transformation functions, stopping if any intermediate result is nullish.
import { map } from '@ffsm/nullish';
// Transform data with type conversion
const length = map('Hello, World!', (str) => str.length);
// length: 13
// Process user data
const userAge = map(
getUserData(),
(data) => data.user,
(user) => user.profile,
(profile) => profile.age
);
// Returns age or null/undefined if any step fails
tryNull
Execute a function and return its result, or null if an error is thrown.
import { tryNull } from '@ffsm/nullish';
// Safely parse JSON
const userData = tryNull(() => JSON.parse(userDataString));
// Safely access DOM elements
const element = tryNull(() =>
document.getElementById('app')?.getBoundingClientRect()
);
hocTryNull
Higher-order function that wraps a function to catch errors and return null instead.
import { hocTryNull } from '@ffsm/nullish';
// Create a safe version of JSON.parse
const safeParse = hocTryNull(JSON.parse);
// Use it without try/catch blocks
const config = safeParse(configString);
const user = safeParse(userString);
isNullishOrEmpty
Check if a value is nullish, an empty array, an empty object, or an empty string.
import { isNullishOrEmpty } from '@ffsm/nullish';
// Validate form inputs
if (isNullishOrEmpty(username)) {
showError('Username is required');
}
// Check if data is available before processing
if (!isNullishOrEmpty(searchResults)) {
displayResults(searchResults);
} else {
showNoResultsMessage();
}
coalesce
Return the first non-nullish value from the provided arguments, or null if all are nullish.
import { coalesce } from '@ffsm/nullish';
// Get user display name from multiple sources
const displayName = coalesce(
user.nickname,
user.username,
user.email,
'Anonymous User'
);
// Use with configuration
const apiUrl = coalesce(
process.env.API_URL,
config.apiUrl,
'https://api.default.com'
);
coalesceRight
Return the last non-nullish value from the provided arguments, or null if all are nullish.
import { coalesceRight } from '@ffsm/nullish';
// Prioritize later values (useful for overrides)
const theme = coalesceRight(
defaultTheme, // Lowest priority
userTheme, // Medium priority
sessionTheme // Highest priority
);
// Configuration with specific overrides
const timeout = coalesceRight(
1000, // Default
globalConfig.timeout, // Global override
requestConfig.timeout // Specific override
);
every
Check if every element in an array is not nullish.
import { every } from '@ffsm/nullish';
// Validate required fields
const requiredFields = [name, email, password];
if (every(requiredFields)) {
submitForm();
} else {
showErrorMessage('All fields are required');
}
// Ensure complete data before processing
if (every(userData)) {
processUserData(userData);
}
some
Check if at least one element in an array is not nullish.
import { some } from '@ffsm/nullish';
// Check if any contact method is available
const contactMethods = [user.email, user.phone, user.address];
if (some(contactMethods)) {
enableContactButton();
} else {
showWarning('No contact methods available');
}
swap
Swap null with undefined and vice versa.
import { swap } from '@ffsm/nullish';
// Convert null to undefined for optional parameters
function processUser(user, options = swap(null)) {
// Now options is undefined instead of null
}
// Convert undefined to null for API requirements
const payload = {
name: user.name,
email: user.email,
phone: swap(user.phone), // Convert undefined to null if phone is undefined
};
until
Processes a value through a series of functions until a non-nullish result is produced.
import { until } from '@ffsm/nullish';
// Finding the first available value in a fallback chain
const username = until(
null,
() => user.preferredName,
() => user.firstName + ' ' + user.lastName,
() => 'Guest_' + user.id,
() => 'Anonymous'
);
// Returns the first non-nullish value from the chain of attempts
// Finding a valid configuration value
const apiEndpoint = until(
config.customEndpoint, // If this exists, use it immediately
() => process.env.API_ENDPOINT,
() => localStorage.getItem('apiEndpoint'),
() => 'https://api.default.com'
);
// Generating and validating in a single chain
const validId = until(
null,
() => generateRandomId(),
(id) => (isValidFormat(id) ? id : null), // Return null to try next function
() => 'default-id-12345'
);
// Early return if value already exists
const existingData = until(
cachedData, // If not nullish, functions won't be executed
() => fetchFromDatabase(),
() => fetchFromAPI()
);
Key Features
- Early Return: If the initial value is not nullish, returns immediately without executing any functions
- Sequential Processing: Applies functions in order until a non-nullish result is found
- Fallback Chain: Perfect for implementing priority-based fallback strategies
- Short-Circuit Evaluation: Stops processing as soon as a valid value is found
- Recovery Mechanism: Can be used to recover from nullish values with multiple strategies
When to Use
Use until
when you have multiple ways to obtain a value and want to try them in a specific order until one succeeds. It's particularly useful for:
- Implementing fallback chains for configuration values
- Setting default values with multiple alternatives
- Attempting recovery operations in sequence
- Loading data from multiple possible sources in order of preference
Unlike map
which stops when it encounters a nullish value, until
stops when it finds a non-nullish value, making it ideal for fallback scenarios.
Type Safety Benefits
All functions in this package are designed with TypeScript type predicates, which means they provide excellent type narrowing in conditional blocks:
// Example of type narrowing with isNullish
function processUser(user: User | null | undefined) {
if (isNullish(user)) {
// TypeScript knows user is null | undefined here
return createDefaultUser();
}
// TypeScript knows user is User here (neither null nor undefined)
return processUserData(user);
}
TypeScript Support
All functions have full TypeScript support with type predicates and type generics, giving you accurate type checking when using them.
License
MIT