Aller au contenu principal

unless()

unless<T, Result>(value, predicate, transformation): T | Result

Applies a transformation to a value when a predicate is false, otherwise returns the original value.

This is the logical opposite of when.

💎 Why is this a Hidden Gem?

The logical inverse of when. Applies a transformation only if the predicate is false.

remarque

Logical opposite of when.


Type Parameters

T: T

The type of the input value.

Result: Result

The type of the transformed value.


Parameters

value: T

The value to potentially transform.

predicate: (value) => boolean

A function that determines when NOT to apply the transformation.

transformation: (value) => Result

The function to apply when the predicate is false.


Returns: T | Result

The transformed value if predicate is false, otherwise the original value.


See Also

when


Since

2.0.0


Also known as

unless (Ramda) · ❌ (Lodash, es-toolkit, Remeda, Radashi, Effect, Modern Dash, Antfu)


Example

unless(4, (n) => n % 2 !== 0, (n) => n * 2);
// => 8 (4 is not odd, so transformation applies)

unless(3, (n) => n % 2 !== 0, (n) => n * 2);
// => 3 (3 is odd, so no transformation)

unless('hello', (s) => s.trim() === '', (s) => s.toUpperCase());
// => 'HELLO' (not empty, so transformation applies)

unless('', (s) => s.trim() === '', (s) => s.toUpperCase());
// => '' (empty, so no transformation)

How it works?

Applies a transformation only when the predicate returns false. If predicate is true, returns the original value unchanged. Logical opposite of when.

Predicate False (transforms)

Predicate True (skips)

unless vs when

Inputwhen(x, isOdd, double)unless(x, isOdd, double)
3 (odd) transforms → 6 skips → 3
4 (even) skips → 4 transforms → 8

Use Cases

Add defaults only when missing 📌

Add 'https://' prefix only when URL doesn't already have it. Essential for URL normalization and ensuring valid links.

const ensureProto = (url) => 
unless(url, (u) => u.startsWith("http"), (u) => `https://${u}`);

ensureProto("google.com"); // "https://google.com"
ensureProto("https://site.com"); // "https://site.com"

Skip validation for admin users

Apply validation rules only for non-admin users. Critical for permission systems and role-based logic.

const validate = (user) => 
unless(user, (u) => u.isAdmin, (u) => {
if (!u.email) throw new Error("Email required");
return u;
});

Lazy-load images unless already in viewport

Skip lazy-loading for images already visible on initial render. Essential for above-the-fold optimization and Core Web Vitals.

const maybeLazyLoad = (img: HTMLImageElement) =>
unless(img, (el) => el.getBoundingClientRect().top < window.innerHeight, (el) => {
el.loading = "lazy";
return el;
});

document.querySelectorAll("img").forEach(maybeLazyLoad);

Skip overlay backdrop on mobile

Skip rendering the backdrop overlay on mobile where it causes scroll issues. Perfect for responsive overlay components that behave differently on mobile.

const overlayConfig = (config: OverlayConfig) =>
unless(config, () => window.innerWidth >= 768, (c) => ({
...c,
hasBackdrop: false,
fullScreen: true,
}));

// Desktop: keeps backdrop, normal overlay
// Mobile: no backdrop, full screen sheet

Show tooltip unless touch device

Disable hover tooltips on touch devices where they cause UX issues. Perfect for design systems supporting both desktop and mobile.

const maybeTooltip = (content: string) =>
unless(content, () => "ontouchstart" in window, (text) => ({
tooltip: text,
showOnHover: true,
}));

maybeTooltip("Click to edit"); // Desktop: { tooltip: "Click to edit", showOnHover: true }
// Touch device: "Click to edit" (no tooltip wrapper)