Skip to main content

extend

@rotorsoft/act-root


@rotorsoft/act-root / act/src / extend

Function: extend()

extend<S, T>(source, schema, target?): Readonly<S & T>

Defined in: libs/act/src/utils.ts:392

Validates and merges configuration objects.

This function first validates the source object against a Zod schema using validate, then merges it with an optional target object. The source properties override target properties in the result.

Primarily used for configuration management where you want to:

  1. Define default configuration values
  2. Load environment-specific overrides
  3. Validate the final configuration

The framework uses this internally for the config function.

Type Parameters

S

S extends Record<string, unknown>

Source object type (must be a record)

T

T extends Record<string, unknown>

Target object type (must be a record)

Parameters

source

Readonly<S>

The source object to validate and use as overrides

schema

ZodType<S>

Zod schema to validate the source against

target?

Readonly<T>

Optional target object with default values

Returns

Readonly<S & T>

Merged object with validated source overriding target

Throws

ValidationError if source fails schema validation

Examples

import { extend } from "@rotorsoft/act";
import { z } from "zod";

const ConfigSchema = z.object({
host: z.string(),
port: z.number(),
debug: z.boolean()
});

const defaults = { host: "localhost", port: 3000, debug: false };
const overrides = { port: 8080, debug: true };

const config = extend(overrides, ConfigSchema, defaults);
// Result: { host: "localhost", port: 8080, debug: true }
import { extend } from "@rotorsoft/act";
import { z } from "zod";

const DbConfigSchema = z.object({
host: z.string(),
port: z.number(),
database: z.string(),
user: z.string(),
password: z.string()
});

const defaults = {
host: "localhost",
port: 5432,
database: "myapp_dev",
user: "postgres",
password: "dev"
};

const envConfig = {
host: process.env.DB_HOST || "localhost",
port: parseInt(process.env.DB_PORT || "5432"),
database: process.env.DB_NAME || "myapp_dev",
user: process.env.DB_USER || "postgres",
password: process.env.DB_PASSWORD || "dev"
};

// Validates environment config and merges with defaults
const dbConfig = extend(envConfig, DbConfigSchema, defaults);
// This is how Act's config() function uses extend internally:
import { extend } from "@rotorsoft/act";
import { z } from "zod";

const BaseSchema = z.object({
env: z.enum(["development", "test", "staging", "production"]),
logLevel: z.enum(["fatal", "error", "warn", "info", "debug", "trace"]),
sleepMs: z.number().int().min(0).max(5000)
});

const packageData = { name: "my-app", version: "1.0.0" };
const runtimeConfig = { env: "production", logLevel: "info", sleepMs: 100 };

const config = extend(
{ ...packageData, ...runtimeConfig },
BaseSchema,
packageData
);
import { extend, ValidationError } from "@rotorsoft/act";
import { z } from "zod";

const schema = z.object({
apiKey: z.string().min(32),
timeout: z.number().positive()
});

try {
const config = extend(
{ apiKey: "short", timeout: -1 },
schema
);
} catch (error) {
if (error instanceof ValidationError) {
console.error("Invalid configuration:", error.details);
}
}

See