Skip to content

quickmodel / IQAdvancedOptions

Interface: IQAdvancedOptions<TTypeMap> ​

Advanced options for @Quick() decorator (second parameter).

Now with proper key inference from the typeMap.

See ​

Examples ​

Simple discriminator by field name:

typescript
interface IContent { type: 'content'; text: string; }
interface IMetadata { type: 'metadata'; tags: string[]; }

@Quick({
  items: [Content, Metadata]
}, {
  discriminators: {
    items: 'type'  // ✅ TypeScript knows 'items' is a valid key
  }
})
class Data extends QModel<IData> {
  declare items: (Content | Metadata)[];
}

With explicit mapping:

typescript
@Quick({
  items: [Content, Metadata]
}, {
  discriminators: {
    items: {  // ✅ TypeScript knows 'items' is a valid key
      field: 'type',
      mapping: {
        'content': Content,    // ✅ Must be Content or Metadata
        'metadata': Metadata
      }
    }
  }
})

With custom type guard function (with proper type inference):

typescript
@Quick({
  items: [Content, Metadata]
}, {
  discriminators: {
    items: (data) => {
      // ✅ TypeScript knows this must return Content or Metadata
      if ('text' in data) return Content;
      if ('tags' in data) return Metadata;
      return Content;  // ✅ Fallback must also be Content or Metadata
    }
  }
})
``` *

## Type Parameters

### TTypeMap

`TTypeMap` *extends* `Record`\<`string`, `unknown`\> = `Record`\<`string`, `unknown`\>

The type map passed to @Quick() (first parameter)

## Properties

### alias?

> `optional` **alias?**: `Record`\<`string`, `string`\>

Key alias map for input remapping (API → model) and output remapping (model → API).

Maps each model property name to its external alias key. During construction, alias keys
in the input are automatically renamed to the property name. During `serialize()`, property
names are renamed back to the alias keys in the output.

**Type-safe alternative to `@QAlias`**: unlike `@QAlias`, the alias map provided here is
visible to TypeScript at compile time when combined with the second generic of `QModel`.
Pass the same map as `TAliasMap` to `QModel<TInterface, TAliasMap>` so that `serialize()`
returns a correctly typed object with alias keys — enabling IDE autocomplete without casts.

#### Example

```typescript
type IUserAliases = { firstName: 'first_name'; lastName: 'last_name' };

@Quick({}, { alias: { firstName: 'first_name', lastName: 'last_name' } })
class User extends QModel<IUser, IUserAliases> {
  declare firstName: string;
  declare lastName: string;
}

const user = new User({ first_name: 'Alice', last_name: 'Smith' });
user.firstName;             // 'Alice'
user.$qSerialize().first_name; // 'Alice' — typed correctly ✅

coercionStrategy? ​

optional coercionStrategy?: "strict" | "loose"

Type coercion strategy (per-model override).


dateStrategy? ​

optional dateStrategy?: "iso" | "timestamp" | "native"

Date serialization strategy.


discriminators? ​

optional discriminators?: { [K in string | number | symbol]?: IQDiscriminatorConfig<IQExtractConstructors<TTypeMap[K]>, IQExtractValidDiscriminatorKeys<TTypeMap[K]> & string> }

Discriminator configuration for union type properties.

Maps property names to their discriminator configuration. Keys are inferred from the typeMap, and discriminator functions are typed to return only the constructors declared in the typeMap. String discriminators are validated to be common keys across all types.

  • string: Field name to use as discriminator (validated against common keys)
  • function: Custom type guard function (properly typed)
  • object: Full configuration with field and mapping

enableDebugLogs? ​

optional enableDebugLogs?: boolean

Enable internal debug logging for this model. Useful for troubleshooting transformation or validation issues.


excludeFields? ​

optional excludeFields?: string[]

Fields to permanently exclude from serialization (serialize() / toJSON()).

Useful for WeakMap/WeakSet properties, passwords, internal caches, or any field that should never appear in the output regardless of how the model is serialized.

Unlike the runtime omit option (which is per-call), excludeFields is declared once in the decorator and is always applied automatically.

Deserialization is NOT affected — the fields are still populated on the instance.

Example ​

typescript
@Quick({ cache: WeakMap }, { excludeFields: ['cache'] })
class Session extends QModel<ISession> {
  declare id: string;
  declare cache: WeakMap<object, any>; // runtime only — never in JSON
}

@Quick({}, { excludeFields: ['password', '_checksum'] })
class User extends QModel<IUser> {
  declare id: number;
  declare password: string; // never serialized
}

exposeUnsetFields? ​

optional exposeUnsetFields?: boolean

Include fields with undefined/null values in the serialized output.

  • true: key: null or key: undefined are included in JSON.
  • false (default): Keys with undefined values are omitted (standard JSON behavior for undefined).

history? ​

optional history?: IQHistoryClassConfig

History trail configuration for this model class.

When enabled: true, every $qPatch(), $qCopy(), and $qFrom() call records a chronological mutation log accessible via instance.$qHistory.

The constructor is not recorded — only mutations are tracked. When disabled (the default), no overhead is incurred: $qHistory returns a no-op NullHistoryHandle and the internal array is never allocated.

Example ​

typescript
@Quick({ name: 'string' }, { history: { enabled: true, maxEntries: 50 } })
class Contract extends QModel<IContract> {
  declare name: string;
}

const c = new Contract({ name: 'v1' });
c.$qPatch({ name: 'v2' });
c.$qHistory.value;
// → [{ method: 'patch', at: Date, changes: { name: { from: 'v1', to: 'v2' } } }]

See ​


integrityErrorStrategy? ​

optional integrityErrorStrategy?: "failFast" | "accumulate"

Strategy for reporting integrity errors.

  • failFast: Returns immediately on the first error encountered (optimized).
  • accumulate (default): Collects and returns all integrity errors.

maxArrayLength? ​

optional maxArrayLength?: number

Maximum allowed length for arrays during deserialization. Overrides the global default limit for this model.

Used to mitigate DoS attacks via massive arrays.

Default ​

ts
10000 (configurable via global config)

mockers? ​

optional mockers?: { [K in string | number | symbol]?: IQMockerFn }

Custom mock generators for specific properties.

Allows defining how to generate mock data for specific fields. Critical when using custom transformers where the default mock generation (which infers from type) might produce invalid/incompatible data.

Example ​

typescript
@Quick({
  sku: (val) => `ITEM-${val}` // Custom transformer
}, {
  mockers: {
    // Generate valid SKU base for the transformer
    sku: () => faker.string.alphanumeric(8)
  }
})

normalization? ​

optional normalization?: object

String normalization options (per-model override).

emptyStringAsNull? ​

optional emptyStringAsNull?: boolean

trimStrings? ​

optional trimStrings?: boolean


nullToUndefined? ​

optional nullToUndefined?: boolean

If true, converts all null values to undefined.


performance? ​

optional performance?: object

Performance optimization settings.

disableSafetyChecks? ​

optional disableSafetyChecks?: boolean

Disables redundant runtime safety checks (like Object.freeze) when data source is trusted. Use with caution.

Default ​
ts
false

serializers? ​

optional serializers?: { [K in string | number | symbol]?: IQSerializerFn }

Custom serializers for specific properties.

Allows defining the reverse transformation logic (Model -> Interface) for specific fields. Critical when using custom transformers that function as one-way mappings, or when the default serialization behavior needs to be overridden for specific fields.

Example ​

typescript
@Quick({
  date: Date
}, {
  transformers: {
    // Deserialize: seconds -> Date
    date: (val) => new Date(val * 1000)
  },
  serializers: {
    // Serialize: Date -> seconds
    date: (val: Date) => Math.floor(val.getTime() / 1000)
  }
})

spoofMethod? ​

optional spoofMethod?: IQSpoofMethod

HTTP method to spoof via a _method field appended as the first entry of the resulting FormData when calling toFormData().

Enables frameworks such as Laravel, Symfony, and Rails to receive PUT, PATCH, DELETE, WebDAV, and other non-POST methods through a standard multipart/form-data POST request.

Cascading precedence (lowest → highest): QConfig.defaults.spoofMethod → @Quick({}, { spoofMethod }) → toFormData({ spoofMethod })

See ​

IQSpoofMethod for the full list of valid values


stripInternalIdentifiers? ​

optional stripInternalIdentifiers?: boolean | string[]

Automatically excludes properties starting with internal prefixes (default: _, $) from population.

  • true: Strips properties starting with _ or $ (or global configured prefixes).
  • false: Allows internal properties.
  • string[]: Strips properties starting with these specific prefixes (overrides global).

Used to protect internal state from mass-assignment attacks.


trace? ​

optional trace?: object

Per-model structured trace configuration.

Overrides the global QConfig.configure({ defaults: { trace: { ... } } }) setting for this specific model class only.

events? ​

optional events?: IQTraceEvent[]

Filter which lifecycle events to trace for this model. When omitted, all events matching verbosity are traced.

sink? ​

optional sink?: (entry) => void

Custom sink for trace entries from this model only. When provided, entries are forwarded here instead of console.

Parameters ​
entry ​

IQTraceEntry

Returns ​

void

verbosity? ​

optional verbosity?: IQTraceVerbosity

Minimum verbosity level to emit for this model. Overrides the global trace.verbosity.

Example ​

typescript
@Quick({ createdAt: Date }, {
  trace: {
    verbosity: 'verbose',
    events: ['rule-fail', 'construction'],
  }
})
class OrderModel extends QModel<IOrder> { ... }

transformCase? ​

optional transformCase?: IQCaseOptions

Case transformation strategy for input (API -> Model) and output (Model -> API).


transformerOptions? ​

optional transformerOptions?: { [K in string | number | symbol]?: Record<string, unknown> }

Configuration options passed to transformers.

Allows configuring specific limits or behaviors for built-in transformers. e.g. maxBytes for ArrayBuffer, maxItems for TypedArray.

Example ​

typescript
@Quick({
  video: ArrayBuffer
}, {
  transformerOptions: {
    video: { maxBytes: 5_000_000 } // Allow 5MB
  }
})

transformers? ​

optional transformers?: { [K in string | number | symbol]?: IQTransformerFn }

Custom transformers for specific properties.

Allows overriding the default deserialization logic for specific fields by providing a custom function that receives the raw value and returns the transformed value.

Example ​

typescript
@Quick({
  status: String // Normal string
}, {
  transformers: {
    status: (val) => val.toUpperCase() // Custom transformation
  }
})

unknownPropertyPolicy? ​

optional unknownPropertyPolicy?: "error" | "keep" | "strip"

Behavior when encountering properties in input data that are not defined in the model.

  • keep (default): Preserves extra properties.
  • strip: Silently removes extra properties.
  • error: Throws an error.

validationTrigger? ​

optional validationTrigger?: "manual" | "construction"

When to run integrity check.

  • manual (default): Check must be triggered explicitly via .$qCheckIntegrity().
  • construction: Check runs automatically after population. Throws if it fails.