objectenvy / override
Function: override()
ts
function override<T>(
defaults,
config,
options?): T;Defined in: objectEnvy.ts:789
Apply default values to a config object, filling in only the keys that are absent in config.
Type Parameters
| Type Parameter |
|---|
T extends ConfigObject |
Parameters
| Parameter | Type | Description |
|---|---|---|
defaults | T | The base values to fall back to for missing keys. |
config | Partial<T> | The user-supplied values; these always take precedence over defaults. |
options | MergeOptions | Merge options, including arrayMergeStrategy. |
Returns
T
A new object combining config (priority) with any keys absent from config filled from defaults.
Remarks
override is a one-directional merge: config wins. For every key in defaults, if config already has a value for that key it is kept; otherwise the default is used. Nested objects are traversed recursively so deeply-nested defaults are filled in without overwriting any key that config sets at any depth.
Array merging is controlled by options.arrayMergeStrategy:
'replace'(default): the config array replaces the default array entirely.'concat': config array followed by any remaining defaults array elements.'concat-unique': same as concat but duplicate primitives are removed.
Use When
- You want to layer environment config on top of hard-coded application defaults.
- You have partial user-supplied configs and need safe fallback values for unset fields.
- You're building a plugin or middleware layer that injects sensible defaults without overriding user intent.
Avoid When
- You need a symmetric deep merge where neither object has priority — use
merge()instead. - You need to merge more than two objects at once — chain multiple
override()calls.
Pitfalls
- NEVER mutate the
defaultsorconfigarguments after callingoverride()— BECAUSE the returned object is a shallow copy at each level; nested sub-objects are NOT deep-cloned, so mutations to deeply nested objects propagate back through the shared reference. - NEVER rely on
override()to handle class instances or special objects (Date, Map, Set) — BECAUSE the function checkstypeof === 'object'and recurses, which may produce unexpected results for non-plain-object values.
Examples
ts
import { objectify, override } from 'objectenvy';
const defaults = { port: 3000, log: { level: 'info', path: '/var/log' } };
const envConfig = objectify({ env: process.env, prefix: 'APP' });
const config = override(defaults, envConfig);
// { port: 3000, log: { level: 'debug', path: '/var/log' } }
// env wins where it has values; defaults fill missing keysts
// Append default tags when env provides its own list
import { override } from 'objectenvy';
const defaults = { tags: ['v1'] };
const config = { tags: ['prod'] };
const result = override(defaults, config, { arrayMergeStrategy: 'concat' });
// { tags: ['prod', 'v1'] }See
merge for a symmetric deep merge (neither object has priority)
Default Value
options.arrayMergeStrategy defaults to 'replace'