API reference@evolu/commonType › withDefault

Call Signature

function withDefault<T, Value>(
  property: OptionalProperty<T> & {
    type: ValidateDefaultType<T, true>;
  },
  value: Value,
): WithDefaultProperty<T, Value, "replace">;

Defined in: packages/common/src/Type.ts:12005

Supplies a decoded default for absence accepted by another Type.

You might not need this: use ?? where a value is consumed if the default does not need to become part of the decoded data. By default, replacement loses the distinction between absence and an explicitly supplied value. Set strategy: "preserve" to retain it.

Defaults apply after decoding, to null and undefined accepted by the wrapped Type, and to missing properties when wrapping optional. Types whose Output excludes both null and undefined require optional; otherwise there is no accepted absence to default. Invalid supplied values still fail. An optional property does not accept an explicit undefined unless its Type does. The default must be an Output of the wrapped Type; it is checked when constructing the declaration. It may itself be null or undefined when the wrapped Output accepts that value.

Omitting strategy returns the effective value and encodes it as supplied data. strategy: "preserve" returns Defaulted and restores absence when encoding. A supplied value equal to the default still has defaultUsed: false. Preserved defaults must equal the configured value: Data values use structural equality, and other values use reference identity. Every decoded absence reuses the configured default by reference; defaults are not cloned. Treat default values as immutable, like other Type declarations.

Pass the default value as the second argument. Add { strategy: "preserve" } as the third argument to retain supplied-input evidence. Explicit strategy: "replace" is not accepted.

Example

import {
  assertEqual,
  assertErr,
  assertOk,
  Boolean,
  nullOr,
  object,
  optional,
  withDefault,
} from "@evolu/common";

const Settings = object({
  enabled: withDefault(optional(Boolean), true, {
    strategy: "preserve",
  }),
});

const missing = Settings.fromUnknown({});
assertOk(missing, {
  enabled: { value: true, defaultUsed: true, original: "missing" },
});
assertEqual(Settings.to(missing.value), {});

assertOk(Settings.fromUnknown({ enabled: true }), {
  enabled: { value: true, defaultUsed: false },
});
assertErr(Settings.fromUnknown({ enabled: undefined }));

const Enabled = withDefault(nullOr(Boolean), true);

assertOk(Enabled.fromUnknown(null), true);
assertEqual(Enabled.to(true), true);

Call Signature

function withDefault<T, Value>(
  property: OptionalProperty<T> & {
    type: ValidateDefaultType<T, true>;
  },
  value: Value,
  options: {
    strategy: "preserve";
  },
): WithDefaultProperty<T, Value, "preserve">;

Defined in: packages/common/src/Type.ts:12014

Supplies a decoded default for absence accepted by another Type.

You might not need this: use ?? where a value is consumed if the default does not need to become part of the decoded data. By default, replacement loses the distinction between absence and an explicitly supplied value. Set strategy: "preserve" to retain it.

Defaults apply after decoding, to null and undefined accepted by the wrapped Type, and to missing properties when wrapping optional. Types whose Output excludes both null and undefined require optional; otherwise there is no accepted absence to default. Invalid supplied values still fail. An optional property does not accept an explicit undefined unless its Type does. The default must be an Output of the wrapped Type; it is checked when constructing the declaration. It may itself be null or undefined when the wrapped Output accepts that value.

Omitting strategy returns the effective value and encodes it as supplied data. strategy: "preserve" returns Defaulted and restores absence when encoding. A supplied value equal to the default still has defaultUsed: false. Preserved defaults must equal the configured value: Data values use structural equality, and other values use reference identity. Every decoded absence reuses the configured default by reference; defaults are not cloned. Treat default values as immutable, like other Type declarations.

Pass the default value as the second argument. Add { strategy: "preserve" } as the third argument to retain supplied-input evidence. Explicit strategy: "replace" is not accepted.

Example

import {
  assertEqual,
  assertErr,
  assertOk,
  Boolean,
  nullOr,
  object,
  optional,
  withDefault,
} from "@evolu/common";

const Settings = object({
  enabled: withDefault(optional(Boolean), true, {
    strategy: "preserve",
  }),
});

const missing = Settings.fromUnknown({});
assertOk(missing, {
  enabled: { value: true, defaultUsed: true, original: "missing" },
});
assertEqual(Settings.to(missing.value), {});

assertOk(Settings.fromUnknown({ enabled: true }), {
  enabled: { value: true, defaultUsed: false },
});
assertErr(Settings.fromUnknown({ enabled: undefined }));

const Enabled = withDefault(nullOr(Boolean), true);

assertOk(Enabled.fromUnknown(null), true);
assertEqual(Enabled.to(true), true);

Call Signature

function withDefault<T, Value>(
  type: T &
    ValidateOptionalPropertyType<T> &
    [
      "WithDefault" extends InferErrors<T>["type"]
        ? "⛔ Type error: Error type must not duplicate an error inherited from the parent Type."
        : never,
    ] extends [never]
    ? unknown
    : "WithDefault" extends InferErrors<T>["type"]
      ? "⛔ Type error: Error type must not duplicate an error inherited from the parent Type."
      : never & [DefaultOriginal<T>] extends [never]
        ? "⛔ Type error: withDefault requires an optional property or a Type whose Output includes null or undefined."
        : unknown,
  value: Value,
): WithDefaultType<T, Value, "replace">;

Defined in: packages/common/src/Type.ts:12024

Supplies a decoded default for absence accepted by another Type.

You might not need this: use ?? where a value is consumed if the default does not need to become part of the decoded data. By default, replacement loses the distinction between absence and an explicitly supplied value. Set strategy: "preserve" to retain it.

Defaults apply after decoding, to null and undefined accepted by the wrapped Type, and to missing properties when wrapping optional. Types whose Output excludes both null and undefined require optional; otherwise there is no accepted absence to default. Invalid supplied values still fail. An optional property does not accept an explicit undefined unless its Type does. The default must be an Output of the wrapped Type; it is checked when constructing the declaration. It may itself be null or undefined when the wrapped Output accepts that value.

Omitting strategy returns the effective value and encodes it as supplied data. strategy: "preserve" returns Defaulted and restores absence when encoding. A supplied value equal to the default still has defaultUsed: false. Preserved defaults must equal the configured value: Data values use structural equality, and other values use reference identity. Every decoded absence reuses the configured default by reference; defaults are not cloned. Treat default values as immutable, like other Type declarations.

Pass the default value as the second argument. Add { strategy: "preserve" } as the third argument to retain supplied-input evidence. Explicit strategy: "replace" is not accepted.

Example

import {
  assertEqual,
  assertErr,
  assertOk,
  Boolean,
  nullOr,
  object,
  optional,
  withDefault,
} from "@evolu/common";

const Settings = object({
  enabled: withDefault(optional(Boolean), true, {
    strategy: "preserve",
  }),
});

const missing = Settings.fromUnknown({});
assertOk(missing, {
  enabled: { value: true, defaultUsed: true, original: "missing" },
});
assertEqual(Settings.to(missing.value), {});

assertOk(Settings.fromUnknown({ enabled: true }), {
  enabled: { value: true, defaultUsed: false },
});
assertErr(Settings.fromUnknown({ enabled: undefined }));

const Enabled = withDefault(nullOr(Boolean), true);

assertOk(Enabled.fromUnknown(null), true);
assertEqual(Enabled.to(true), true);

Call Signature

function withDefault<T, Value>(
  type: T &
    ValidateOptionalPropertyType<T> &
    [
      "WithDefault" extends InferErrors<T>["type"]
        ? "⛔ Type error: Error type must not duplicate an error inherited from the parent Type."
        : never,
    ] extends [never]
    ? unknown
    : "WithDefault" extends InferErrors<T>["type"]
      ? "⛔ Type error: Error type must not duplicate an error inherited from the parent Type."
      : never & [DefaultOriginal<T>] extends [never]
        ? "⛔ Type error: withDefault requires an optional property or a Type whose Output includes null or undefined."
        : unknown,
  value: Value,
  options: {
    strategy: "preserve";
  },
): WithDefaultType<T, Value, "preserve">;

Defined in: packages/common/src/Type.ts:12031

Supplies a decoded default for absence accepted by another Type.

You might not need this: use ?? where a value is consumed if the default does not need to become part of the decoded data. By default, replacement loses the distinction between absence and an explicitly supplied value. Set strategy: "preserve" to retain it.

Defaults apply after decoding, to null and undefined accepted by the wrapped Type, and to missing properties when wrapping optional. Types whose Output excludes both null and undefined require optional; otherwise there is no accepted absence to default. Invalid supplied values still fail. An optional property does not accept an explicit undefined unless its Type does. The default must be an Output of the wrapped Type; it is checked when constructing the declaration. It may itself be null or undefined when the wrapped Output accepts that value.

Omitting strategy returns the effective value and encodes it as supplied data. strategy: "preserve" returns Defaulted and restores absence when encoding. A supplied value equal to the default still has defaultUsed: false. Preserved defaults must equal the configured value: Data values use structural equality, and other values use reference identity. Every decoded absence reuses the configured default by reference; defaults are not cloned. Treat default values as immutable, like other Type declarations.

Pass the default value as the second argument. Add { strategy: "preserve" } as the third argument to retain supplied-input evidence. Explicit strategy: "replace" is not accepted.

Example

import {
  assertEqual,
  assertErr,
  assertOk,
  Boolean,
  nullOr,
  object,
  optional,
  withDefault,
} from "@evolu/common";

const Settings = object({
  enabled: withDefault(optional(Boolean), true, {
    strategy: "preserve",
  }),
});

const missing = Settings.fromUnknown({});
assertOk(missing, {
  enabled: { value: true, defaultUsed: true, original: "missing" },
});
assertEqual(Settings.to(missing.value), {});

assertOk(Settings.fromUnknown({ enabled: true }), {
  enabled: { value: true, defaultUsed: false },
});
assertErr(Settings.fromUnknown({ enabled: undefined }));

const Enabled = withDefault(nullOr(Boolean), true);

assertOk(Enabled.fromUnknown(null), true);
assertEqual(Enabled.to(true), true);