Overview
The always() decoder accepts any input, completely ignores it, and always returns the provided value instead. This is useful for manually adding extra fields to object decoders or injecting constant values during validation.
Basic Usage
import { always } from 'decoders';
const timestampDecoder = always(() => new Date());
const result1 = timestampDecoder.verify('anything');
const result2 = timestampDecoder.verify({ foo: 'bar' });
const result3 = timestampDecoder.verify(null);
// All return a Date instance (current timestamp)
Type Signature
// With scalar value
function always<C extends Scalar>(value: C): Decoder<C>;
// With any value or function
function always<T>(value: T | (() => T)): Decoder<T>;
Where Scalar is string | number | boolean | null | undefined | symbol.
Parameters
The value to always return. Can be a constant value or a function that returns the value. If a function is provided, it will be called each time the decoder runs.
Return Value
Returns a Decoder<T> that accepts any input and always returns the specified value.
Examples
Adding computed fields to objects
import { object, string, number, always } from 'decoders';
const userDecoder = object({
id: number,
name: string,
// Add a timestamp field that's always the current time
createdAt: always(() => new Date()),
// Add a constant version field
version: always('v1'),
});
const user = userDecoder.verify({
id: 123,
name: 'Alice',
// Note: createdAt and version are not in the input
});
// Result: {
// id: 123,
// name: 'Alice',
// createdAt: Date (current time),
// version: 'v1'
// }
Default values
import { object, string, always } from 'decoders';
const configDecoder = object({
apiUrl: string,
timeout: always(5000),
retries: always(3),
});
const config = configDecoder.verify({
apiUrl: 'https://api.example.com',
});
// Result: {
// apiUrl: 'https://api.example.com',
// timeout: 5000,
// retries: 3
// }
With functions for dynamic values
import { object, string, always } from 'decoders';
let counter = 0;
const itemDecoder = object({
name: string,
// Each item gets a unique ID
id: always(() => counter++),
// Each item gets a UUID
uuid: always(() => crypto.randomUUID()),
});
const item1 = itemDecoder.verify({ name: 'First' });
// { name: 'First', id: 0, uuid: '...' }
const item2 = itemDecoder.verify({ name: 'Second' });
// { name: 'Second', id: 1, uuid: '...' }
Injecting context or metadata
import { object, string, always } from 'decoders';
const logEntryDecoder = object({
message: string,
level: string,
// Automatically add metadata
timestamp: always(() => Date.now()),
hostname: always(() => process.env.HOSTNAME || 'unknown'),
environment: always(process.env.NODE_ENV || 'development'),
});
const log = logEntryDecoder.verify({
message: 'User logged in',
level: 'info',
});
// Result includes timestamp, hostname, and environment
Constant vs function values
import { always } from 'decoders';
// Using a constant value (evaluated once)
const constantDecoder = always(new Date());
const result1 = constantDecoder.verify('anything');
const result2 = constantDecoder.verify('anything');
// result1 and result2 have the SAME Date instance
// Using a function (evaluated each time)
const functionDecoder = always(() => new Date());
const result3 = functionDecoder.verify('anything');
const result4 = functionDecoder.verify('anything');
// result3 and result4 have DIFFERENT Date instances
When passing objects or arrays directly to always(), the same instance is reused:const decoder = always({ value: 0 });
const result1 = decoder.verify('a');
const result2 = decoder.verify('b');
result1.value = 10;
console.log(result2.value); // 10 (same object!)
Use a function to create new instances:const decoder = always(() => ({ value: 0 }));
const result1 = decoder.verify('a');
const result2 = decoder.verify('b');
result1.value = 10;
console.log(result2.value); // 0 (different objects)
Use Cases
- Adding timestamps: Inject creation or modification times
- Version fields: Add API or schema version information
- Default configuration: Provide default values that aren’t in the input
- Computed fields: Generate IDs, UUIDs, or other derived values
- Environment injection: Add environment-specific data to validated objects
- Testing: Inject mock data or test values
Difference from constant()
| Decoder | Validates Input? | Returns |
|---|
constant(value) | Yes (must match exactly) | The matched value |
always(value) | No (accepts anything) | The specified value |
import { constant, always } from 'decoders';
// constant: validates the input
constant('hello').verify('hello'); // OK
constant('hello').verify('world'); // Error
// always: ignores the input
always('hello').verify('hello'); // Returns 'hello'
always('hello').verify('world'); // Also returns 'hello'
always('hello').verify(123); // Still returns 'hello'
constant - Validates exact literal values
optional - Provides default values for undefined
nullable - Provides default values for null
See Also