Category: number Since: 1.0.0 Tags: number, clamp, constrain, bounds, range, limit
clamp
Constrains a numeric value between specified minimum and maximum boundaries.
Usage
import { clamp } from "@petr-ptacek/js-core";
const result = clamp(15, 0, 10);
console.log(result); // 10
const inRange = clamp(5, 0, 10);
console.log(inRange); // 5
const belowMin = clamp(-5, 0, 10);
console.log(belowMin); // 0Why This Utility Exists
JavaScript lacks a built-in clamp function for constraining values within bounds. Common manual implementations require multiple Math.min/Math.max calls or verbose conditional logic. This utility provides a clean, validated solution with proper error handling for invalid ranges.
Signature
function clamp(value: number, min: number, max: number): number;Parameters
value(number): The numeric value to constrain.min(number): The minimum boundary (inclusive).max(number): The maximum boundary (inclusive).
Return Type
Returns the input value constrained to the range [min, max]. If the value is below min, returns min. If the value is above max, returns max. Otherwise returns the original value unchanged.
Throws
- Throws
Errorwhenminis greater thanmax.
Design Notes
The implementation uses Math.min(Math.max(value, min), max) for optimal performance. The function validates that min <= max to prevent logical errors and throws immediately for invalid ranges.
The bounds are inclusive, meaning both min and max values are considered valid results.
When To Use
Use clamp when you need to:
- constrain user input within valid ranges
- limit calculated values to acceptable bounds
- implement slider controls or progress bars
- ensure values stay within domain-specific limits
When Not To Use
Avoid when:
- working with non-numeric values (use custom validation instead)
- you need exclusive bounds (min/max values should not be valid)
- complex validation logic beyond simple range checking is required
- performance is critical and you can guarantee valid inputs
Summary
clamp provides a safe and efficient way to constrain numeric values within specified boundaries with proper validation and error handling.
Snippets
basic.ts
import { clamp } from "@petr-ptacek/js-core";
// Basic clamping examples
console.log("=== Basic Clamping ===");
// Value within range - unchanged
const withinRange = clamp(5, 0, 10);
console.log(`clamp(5, 0, 10) = ${withinRange}`); // 5
// Value above maximum - clamped to max
const aboveMax = clamp(15, 0, 10);
console.log(`clamp(15, 0, 10) = ${aboveMax}`); // 10
// Value below minimum - clamped to min
const belowMin = clamp(-3, 0, 10);
console.log(`clamp(-3, 0, 10) = ${belowMin}`); // 0
// Edge cases - boundary values
const exactMin = clamp(0, 0, 10);
console.log(`clamp(0, 0, 10) = ${exactMin}`); // 0
const exactMax = clamp(10, 0, 10);
console.log(`clamp(10, 0, 10) = ${exactMax}`); // 10error-handling.ts
import { clamp } from "@petr-ptacek/js-core";
// Error handling examples
console.log("=== Error Handling ===");
// Valid usage
try {
const result = clamp(50, 0, 100);
console.log(`✓ Valid range: clamp(50, 0, 100) = ${result}`);
} catch (error) {
console.error(`✗ Error: ${error instanceof Error ? error.message : String(error)}`);
}
// Invalid range - min > max
try {
const result = clamp(50, 100, 0); // Invalid: min(100) > max(0)
console.log(`Result: ${result}`);
} catch (error) {
console.error(`✗ Invalid range: ${error instanceof Error ? error.message : String(error)}`);
}
// Safe clamp wrapper with validation
function safeClamp(value: number, min: number, max: number): number | null {
try {
return clamp(value, min, max);
} catch (_error) {
console.warn(`Invalid clamp parameters: min=${min}, max=${max}`);
return null;
}
}
console.log("\n=== Safe Wrapper ===");
// Valid usage
const validResult = safeClamp(75, 0, 100);
console.log(`Safe clamp result: ${validResult}`); // 75
// Invalid usage - handled gracefully
const invalidResult = safeClamp(75, 200, 100);
console.log(`Safe clamp result: ${invalidResult}`); // null
// Auto-correcting clamp (swaps min/max if needed)
function autoClamp(value: number, bound1: number, bound2: number): number {
const min = Math.min(bound1, bound2);
const max = Math.max(bound1, bound2);
return clamp(value, min, max);
}
console.log("\n=== Auto-correcting Clamp ===");
// Works regardless of parameter order
const result1 = autoClamp(50, 0, 100); // Normal order
const result2 = autoClamp(50, 100, 0); // Swapped order - auto-corrected
console.log(`autoClamp(50, 0, 100) = ${result1}`); // 50
console.log(`autoClamp(50, 100, 0) = ${result2}`); // 50practical-usage.ts
import { clamp } from "@petr-ptacek/js-core";
// User input validation
function processUserInput(userValue: string) {
const numericValue = parseFloat(userValue);
// Clamp to valid percentage range
const percentage = clamp(numericValue, 0, 100);
console.log(`User input "${userValue}" -> ${percentage}%`);
return percentage;
}
console.log("=== User Input Validation ===");
processUserInput("50"); // 50%
processUserInput("150"); // 100%
processUserInput("-20"); // 0%
// Slider/Progress bar implementation
class Slider {
private _value: number = 0;
private min: number;
private max: number;
constructor(min: number = 0, max: number = 100) {
this.min = min;
this.max = max;
}
setValue(value: number): void {
this._value = clamp(value, this.min, this.max);
}
getValue(): number {
return this._value;
}
getPercentage(): number {
const range = this.max - this.min;
return ((this._value - this.min) / range) * 100;
}
}
console.log("\n=== Slider Control ===");
const slider = new Slider(0, 255); // RGB color slider
slider.setValue(128);
console.log(`Value: ${slider.getValue()}, Percentage: ${slider.getPercentage().toFixed(1)}%`);
slider.setValue(300); // Clamped to 255
console.log(`Value: ${slider.getValue()}, Percentage: ${slider.getPercentage().toFixed(1)}%`);
slider.setValue(-50); // Clamped to 0
console.log(`Value: ${slider.getValue()}, Percentage: ${slider.getPercentage().toFixed(1)}%`);
// Game physics - velocity limiting
function updatePlayerVelocity(currentVelocity: number, acceleration: number) {
const MAX_SPEED = 10;
const MIN_SPEED = -10;
const newVelocity = currentVelocity + acceleration;
return clamp(newVelocity, MIN_SPEED, MAX_SPEED);
}
console.log("\n=== Game Physics ===");
let velocity = 0;
velocity = updatePlayerVelocity(velocity, 5); // 5
velocity = updatePlayerVelocity(velocity, 8); // 10 (clamped)
velocity = updatePlayerVelocity(velocity, -25); // -10 (clamped)
console.log(`Final velocity: ${velocity}`);