@league-of-foundry-developers/foundry-vtt-types
Version:
TypeScript type definitions for Foundry VTT
763 lines (680 loc) • 28.5 kB
text/typescript
import type { AnyConstructor, AnyFunction, DeepPartial, InexactPartial, NonNullish } from "#utils";
import type Document from "../abstract/document.d.mts";
/**
* Benchmark the performance of a function, calling it a requested number of iterations.
* @param func - The function to benchmark
* @param iterations - The number of iterations to test
* @param args - Additional arguments passed to the benchmarked function
*/
export function benchmark<F extends AnyFunction>(func: F, iterations: number, ...args: Parameters<F>): Promise<void>;
/**
* A debugging function to test latency or timeouts by forcibly locking the thread for an amount of time.
* @param ms - A number of milliseconds to lock
* @param debug - (default: `false`)
* @returns
*/
export function threadLock(ms: number, debug?: boolean): Promise<void>;
/**
* Wrap a callback in a debounced timeout.
* Delay execution of the callback function until the function has not been called for delay milliseconds
* @param callback - A function to execute once the debounced threshold has been passed
* @param delay - An amount of time in milliseconds to delay
* @returns A wrapped function which can be called to debounce execution
*/
export function debounce<T extends AnyFunction>(callback: T, delay: number): (...args: Parameters<T>) => void;
/**
* Wrap a callback in a throttled timeout.
* Delay execution of the callback function when the last time the function was called was delay milliseconds ago
* @param callback - A function to execute once the throttled threshold has been passed
* @param delay - A maximum amount of time in milliseconds between to execution
* @returns - A wrapped function which can be called to throttle execution
*/
export function throttle<T extends (...args: any[]) => any>(callback: T, delay: number): T;
/**
* A utility function to reload the page with a debounce.
*/
export const debouncedReload: VoidFunction;
export interface DeepCloneOptions {
/**
* Throw an Error if deepClone is unable to clone something instead of returning the original
* @defaultValue `false`
*/
strict?: boolean;
/**
* An internal depth tracker
* @defaultValue `0`
*/
_d?: number;
}
/**
* Quickly clone a simple piece of data, returning a copy which can be mutated safely.
* This method DOES support recursive data structures containing inner objects or arrays.
* This method DOES NOT support advanced object types like Set, Map, or other specialized classes.
* @param original - Some sort of data
* @param options - Options to configure the behaviour of deepClone
* @returns - The clone of that data
* @throws - An Error if deepClone is unable to clone something and strict mode is enabled
*/
export function deepClone<T>(original: T, options?: DeepCloneOptions): T;
export type DiffObjectOptions = InexactPartial<{
/**
* Only recognize differences in other for keys which also exist in original
* @defaultValue `false`
*/
inner?: boolean;
/**
* Apply special logic to deletion keys. They will only be kept if the original object has a
* corresponding key that could be deleted.
* @defaultValue `false`
*/
deletionKeys?: boolean;
/**
* An internal depth tracker
* @defaultValue `0`
*/
_d?: number;
}>;
/**
* Deeply difference an object against some other, returning the update keys and values.
* @param original - An object comparing data against which to compare
* @param other - An object containing potentially different data
* @param options - Additional options which configure the diff operation
* @returns - An object of the data in other which differs from that in original
*/
export function diffObject(original: object, other: object, options?: DiffObjectOptions): object;
/**
* Test if two objects contain the same enumerable keys and values.
* @param a - The first object.
* @param b - The second object.
*/
export function objectsEqual<B extends object>(a: object, b: B): a is B;
/**
* A cheap data duplication trick which is relatively robust.
* For a subset of cases the deepClone function will offer better performance.
* @param original - Some sort of data
* @typeParam T - Type of the original data.
*
* @remarks This function will actually convert any occurrences of `NaN` and `Infinity` to `null`. For ease of use, this
* is _not_ reflected in the type. Be careful if your types might contain `NaN` or `Infinity`!
*/
export function duplicate<T>(original: T): Duplicated<T>;
/**
* The resulting type when using {@link duplicate | `duplicate`} on some data of type `T`.
*
* @typeParam T - Original type.
* @internal
*/
export type Duplicated<T> = T extends NonStringifiable ? never : InnerDuplicated<T>;
/**
* Test whether some class is a subclass of a parent.
* Returns true if the classes are identical.
* @param cls - The class to test
* @param parent - Some other class which may be a parent
* @returns Is the class a subclass of the parent?
*/
export function isSubclass<Parent extends AnyConstructor>(cls: AnyConstructor, parent: Parent): cls is Parent;
/**
* Search up the prototype chain and return the class that defines the given property.
* @param obj - A class instance or class definition which contains a property.
* - If a class instance is passed the property is treated as an instance attribute.
* - If a class constructor is passed the property is treated as a static attribute.
* @param property - The property name
* @returns - The class that defines the property
*/
export function getDefiningClass(cls: AnyConstructor, property: string): AnyConstructor;
/**
* Encode a url-like string by replacing any characters which need encoding
* @param path - A fully-qualified URL or url component (like a relative path)
* @returns An encoded URL string
*/
export function encodeURL(path: string): string;
/**
* Expand a flattened object to be a standard multi-dimensional nested Object by converting all dot-notation keys to
* inner objects.
*
* @param obj - The object to expand
* @returns An expanded object
*
*/
export function expandObject(obj: object): object;
/**
* Filter the contents of some source object using the structure of a template object.
* Only keys which exist in the template are preserved in the source object.
*
* @param source - An object which contains the data you wish to filter
* @param template - An object which contains the structure you wish to preserve
* @param options - Additional options which customize the filtration
* (default: `{}`)
*
* @example Filter an object
* ```typescript
* const source = {foo: {number: 1, name: "Tim", topping: "olives"}, bar: "baz"};
* const template = {foo: {number: 0, name: "Mit", style: "bold"}, other: 72};
* filterObject(source, template); // {foo: {number: 1, name: "Tim"}};
* filterObject(source, template, {templateValues: true}); // {foo: {number: 0, name: "Mit"}};
* ```
*/
export function filterObject(source: object, template: object, options?: FilterObjectOptions): object;
export interface FilterObjectOptions {
/**
* Whether to keep deletion keys
* @defaultValue `false`
*/
deletionKeys?: boolean | undefined;
/**
* Instead of keeping values from the source, instead draw values from the template
* @defaultValue `false`
*/
templateValues?: boolean | undefined;
}
/**
* Flatten a possibly multi-dimensional object to a one-dimensional one by converting all nested keys to dot notation
* @param obj - The object to flatten
* @param _d - Track the recursion depth to prevent overflow. (default: `0`)
* @returns A flattened object
*/
export function flattenObject(obj: object, _d?: number): object;
/**
* Obtain references to the parent classes of a certain class.
* @param cls - An ES6 Class definition
* @returns An array of parent Classes which the provided class extends
*/
export function getParentClasses(cls: AnyConstructor): Array<AnyConstructor>;
export interface GetRouteOptions {
/**
* A path prefix to apply
* (default: `null`)
*/
prefix?: string | null | undefined;
}
/**
* Get the URL route for a certain path which includes a path prefix, if one is set
* @param path - The Foundry URL path
* @returns The absolute URL path
*/
export function getRoute(path: string, { prefix }?: GetRouteOptions): string;
/**
* Learn the underlying data type of some variable. Supported identifiable types include:
* undefined, null, number, string, boolean, function, Array, Set, Map, Promise, Error,
* HTMLElement (client side only), Object (catchall for other object types)
* @param variable - A provided variable
* @returns The named type of the token
*/
export function getType(
variable: unknown,
):
| "Array"
| "Error"
| "HTMLElement"
| "Map"
| "Object"
| "Promise"
| "Set"
| "bigint"
| "boolean"
| "function"
| "null"
| "number"
| "string"
| "symbol"
| "undefined";
/**
* A helper function which tests whether an object has a property or nested property given a string key.
* The string key supports the notation a.b.c which would return true if object[a][b][c] exists
* @param object - The object to traverse
* @param key - An object property with notation a.b.c
* @returns An indicator for whether the property exists
*/
export function hasProperty(object: object, key: string): boolean;
/**
* A helper function which searches through an object to retrieve a value by a string key.
* The string key supports the notation a.b.c which would return object[a][b][c]
* @param object - The object to traverse
* @param key - An object property with notation a.b.c
* @returns The value of the found property
*/
export function getProperty(object: object, key: string): any;
/**
* A helper function which searches through an object to assign a value using a string key
* This string key supports the notation a.b.c which would target object[a][b][c]
* @param object - The object to update
* @param key - The string key
* @param value - The value to be assigned
* @returns Whether the value was changed from its previous value
*/
export function setProperty(object: object, key: string, value: any): boolean;
// Merging into this would be antithetical to its purpose.
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export type InvertableObject = {
readonly [K: PropertyKey]: PropertyKey;
};
export type InvertObject<in out T extends InvertableObject> = {
[K in keyof T as T[K]]: K;
};
/**
* Invert an object by assigning its values as keys and its keys as values.
* @param obj - The original object to invert
* @returns The inverted object with keys and values swapped
*/
export function invertObject<T extends InvertableObject>(obj: T): InvertObject<T>;
/**
* Return whether a target version (v1) is more advanced than some other reference version (v0).
* Supports either numeric or string version comparison with version parts separated by periods.
* @param v1 - The target version
* @param v0 - The reference version
* @returns Is v1 a more advanced version than v0?
*/
export function isNewerVersion(v1: number | string, v0: number | string): boolean;
/**
* Test whether a value is empty-like; either undefined or a content-less object.
* @param value - The value to test
* @returns Is the value empty-like?
*/
export function isEmpty(
value: undefined | null | unknown[] | object | Set<unknown> | Map<unknown, unknown> | NonNullish,
): boolean;
export type MergeObject<T, U, M extends MergeObjectOptions> = UpdateInsert<
DeleteByObjectKeys<T, U, M>,
RemoveDeletingObjectKeys<U, M>,
M
>;
/**
* Update a source object by replacing its keys and values with those from a target object.
*
* @param original - The initial object which should be updated with values from the target
* @param other - A new object whose values should replace those in the source
* (default: `{}`)
* @param options - Additional options which configure the merge
* (default: `{}`)
* @param _d - A privately used parameter to track recursion depth.
* (default: `0`)
* @returns The original source object including updated, inserted, or overwritten records.
*
* @example Control how new keys and values are added
* ```typescript
* mergeObject({k1: "v1"}, {k2: "v2"}, {insertKeys: false}); // {k1: "v1"}
* mergeObject({k1: "v1"}, {k2: "v2"}, {insertKeys: true}); // {k1: "v1", k2: "v2"}
* mergeObject({k1: {i1: "v1"}}, {k1: {i2: "v2"}}, {insertValues: false}); // {k1: {i1: "v1"}}
* mergeObject({k1: {i1: "v1"}}, {k1: {i2: "v2"}}, {insertValues: true}); // {k1: {i1: "v1", i2: "v2"}}
* ```
*
* @example Control how existing data is overwritten
* ```typescript
* mergeObject({k1: "v1"}, {k1: "v2"}, {overwrite: true}); // {k1: "v2"}
* mergeObject({k1: "v1"}, {k1: "v2"}, {overwrite: false}); // {k1: "v1"}
* ```
*
* @example Control whether merges are performed recursively
* ```typescript
* mergeObject({k1: {i1: "v1"}}, {k1: {i2: "v2"}}, {recursive: false}); // {k1: {i2: "v2"}}
* mergeObject({k1: {i1: "v1"}}, {k1: {i2: "v2"}}, {recursive: true}); // {k1: {i1: "v1", i2: "v2"}}
* ```
*
* @example Deleting an existing object key
* ```typescript
* mergeObject({k1: "v1", k2: "v2"}, {"-=k1": null}, {performDeletions: true}); // {k2: "v2"}
* ```
*/
export function mergeObject<
T extends object,
U extends DeepPartial<WithWidenedArrayTypes<T>>,
M extends MergeObjectOptions & { enforceTypes: true },
>(original: T, other?: U, options?: M, _d?: number): MergeObject<T, U, M>;
export function mergeObject<
T extends object,
U extends DeepPartial<Record<keyof T, never>> & object,
M extends MergeObjectOptions & { enforceTypes: true },
>(original: T, other?: U, options?: M, _d?: number): MergeObject<T, U, M>;
export function mergeObject<T extends object, U extends object, M extends MergeObjectOptions & { enforceTypes: true }>(
original: T,
other?: U,
options?: M,
_d?: number,
): never;
export function mergeObject<T extends object, U extends object, M extends MergeObjectOptions>(
original: T,
other?: U,
options?: M,
_d?: number,
): MergeObject<T, U, M>;
export interface MergeObjectOptions {
/**
* Control whether to insert new top-level objects into the resulting structure which do not previously exist in the original object.
* @defaultValue `true`
*/
insertKeys?: boolean | undefined;
/**
* Control whether to insert new nested values into child objects in the resulting structure which did not previously exist in the original object.
* @defaultValue `true`
*/
insertValues?: boolean | undefined;
/**
* Control whether to replace existing values in the source, or only merge values which do not already exist in the original object.
* @defaultValue `true`
*/
overwrite?: boolean | undefined;
/**
* Control whether to merge inner-objects recursively (if true), or whether to simply replace inner objects with a provided new value.
* @defaultValue `true`
*/
recursive?: boolean | undefined;
/**
* Control whether to apply updates to the original object in-place (if true), otherwise the original object is duplicated and the copy is merged.
* @defaultValue `true`
*/
inplace?: boolean | undefined;
/**
* Control whether strict type checking requires that the value of a key in the other object must match the data type in the original data to be merged.
* @defaultValue `false`
*/
enforceTypes?: boolean | undefined;
/**
* Control whether to perform deletions on the original object if deletion keys are present in the other object.
* @defaultValue `false`
*/
performDeletions?: boolean | undefined; // TODO: implement this in the mergeObject return type
}
/**
* A helper function for merging objects when the target key does not exist in the original
* @internal
*/
declare function _mergeInsert(
original: object,
k: PropertyKey,
v: any,
options?: Pick<MergeObjectOptions, "insertKeys" | "insertValues" | "performDeletions">,
_d?: number,
): void;
/**
* A helper function for merging objects when the target key exists in the original
* @internal
*/
declare function _mergeUpdate<T extends object, K extends keyof T>(
original: T,
k: K,
v: any,
options?: Pick<
MergeObjectOptions,
"insertKeys" | "insertValues" | "enforceTypes" | "overwrite" | "recursive" | "performDeletions"
>,
_d?: number,
): void;
/**
* Parse an S3 key to learn the bucket and the key prefix used for the request.
* @param key - A fully qualified key name or prefix path.
*/
export function parseS3URL(key: string): { bucket: string | null; keyPrefix: string };
/**
* Generate a random alphanumeric string ID of a given requested length using `crypto.getRandomValues()`.
* @param length - The length of the random string to generate, which must be at most 16384.
* (default: `16`)
* @returns - A string containing random letters (A-Z, a-z) and numbers (0-9).
*/
export function randomID(length?: number): string;
/**
* Express a timestamp as a relative string
* @param timeStamp - A timestamp string or Date object to be formatted as a relative time
* @returns A string expression for the relative time
*/
export function timeSince(timeStamp: Date | string): string;
/**
* Format a file size to an appropriate order of magnitude.
* @param size - The size in bytes.
* @param options - Additional options. (default: `{}`)
* @returns
*/
export function formatFileSize(size: number, options?: FormatFileSizeOptions): string;
interface FormatFileSizeOptions {
/**
* The number of decimal places to round to.
* @defaultValue `2`
*/
decimalPlaces?: number | undefined;
/**
* The base to use. In base 10 a kilobyte is 1000 bytes. In base 2 it is 1024 bytes.
* @defaultValue `10`
*/
base?: 2 | 10 | undefined;
}
interface ResolvedUUID {
/**
* The original UUID.
*/
uuid: string;
/**
* The type of Document referenced. Legacy compendium UUIDs will not populate this field if the compendium is not active in the World.
*/
type?: Document.Type | undefined;
/**
* The ID of the Document referenced.
*/
id: string;
/**
* The primary Document type of this UUID. Only present if the Document is embedded.
*/
primaryType?: foundry.CONST.PRIMARY_DOCUMENT_TYPES | undefined;
/**
* The primary Document ID of this UUID. Only present if the Document is embedded.
*/
primaryId?: string | undefined;
/**
* The collection that the primary Document belongs to.
*/
collection?: DocumentCollection.Any | undefined;
/**
* Additional Embedded Document parts.
*/
embedded: string[];
/**
* An already-resolved parent Document.
*/
doc?: Document.Any | undefined;
/**
* Either the document type or the parent type. Retained for backwards compatibility.
*/
documentType?: Document.Type | undefined;
/**
* Either the document id or the parent id. Retained for backwards compatibility.
*/
documentId?: string | undefined;
}
interface ParseUUIDOptions {
/**
* A document to resolve relative UUIDs against.
*/
relative?: Document.Any;
}
/**
* Parse a UUID into its constituent parts, identifying the type and ID of the referenced document.
* The ResolvedUUID result also identifies a "primary" document which is a root-level document either in the game
* World or in a Compendium pack which is a parent of the referenced document.
* @param uuid - The UUID to parse.
* @param options - Options to configure parsing behavior.
* @returns - Returns the Collection, Document Type, and Document ID to resolve the parent
* document, as well as the remaining Embedded Document parts, if any.
* @throws - An error if the provided uuid string is incorrectly structured
*/
export function parseUuid(uuid: string, options?: ParseUUIDOptions): ResolvedUUID;
/**
* Resolve a UUID relative to another document.
* The general-purpose algorithm for resolving relative UUIDs is as follows:
* 1. If the number of parts is odd, remove the first part and resolve it against the current document and update the
* current document.
* 2. If the number of parts is even, resolve embedded documents against the current document.
* @param uuid - The UUID to resolve.
* @param relative - The document to resolve against.
* @returns
* @internal
*/
declare function _resolveRelativeUuid(uuid: string, relative: Document.Any): ResolvedUUID;
/**
* Converts an RGB color value to HSV. Conversion formula adapted from http://en.wikipedia.org/wiki/HSV_color_space.
* Assumes r, g, and b are contained in the set [0, 1] and returns h, s, and v in the set [0, 1].
* @param r - The red color value
* @param g - The green color value
* @param b - The blue color value
* @returns The HSV representation
* @deprecated since v10 until v12, rgbToHsv is deprecated in favor of {@link foundry.utils.Color.hsv | `foundry.utils.Color#hsv`}
*/
export function rgbToHsv(r: number, g: number, b: number): [h: number, s: number, v: number];
/**
* Converts an HSV color value to RGB. Conversion formula adapted from http://en.wikipedia.org/wiki/HSV_color_space.
* Assumes h, s, and v are contained in the set [0, 1] and returns r, g, and b in the set [0, 1].
* @param h - The hue
* @param s - The saturation
* @param v - The value
* @returns The RGB representation
* @deprecated since v10 until v12, hsvToRgb is deprecated in favor of {@link foundry.utils.Color.fromHSV | `foundry.utils.Color.fromHSV`}
*/
export function hsvToRgb(h: number, s: number, v: number): [r: number, g: number, b: number];
/**
* Converts a color as an [R, G, B] array of normalized floats to a hexadecimal number.
* @param rgb - Array of numbers where all values are normalized floats from 0.0 to 1.0.
* @returns The numeric color as hexadecimal
* @deprecated since v10 until v12, rgbToHex is deprecated in favor of {@link foundry.utils.Color.fromRGB | `foundry.utils.Color.fromRGB`}
*/
export function rgbToHex(rgb: [r: number, g: number, b: number]): number;
/**
* Convert a hex color code to an RGB array
* @param hex - A hex color number
* @returns An array of [r,g,b] colors normalized on the range of [0,1]
* @deprecated since v10 until v12, hexToRGB is deprecated in favor of {@link foundry.utils.Color.rgb | `foundry.utils.Color#rgb`}
*/
export function hexToRGB(hex: number): [r: number, g: number, b: number];
/**
* Convert a hex color code to an RGBA color string which can be used for CSS styling
* @param hex - A hex color number
* @param alpha - An optional level of transparency
* (default: `1.0`)
* @returns An rgba style string
* @deprecated since v10 until v12, hexToRGBAString is deprecated in favor of {@link foundry.utils.Color.toRGBA | `foundry.utils.Color#toRGBA`}
*/
export function hexToRGBAString(hex: number, alpha?: number): `rgba(${number}, ${number}, ${number})`;
/**
* Convert a string color to a hex integer
* @param color - The string color
* @returns The hexadecimal color code
* @deprecated since v10 until v12, colorStringToHex is deprecated in favor of {@link foundry.utils.Color.from | `foundry.utils.Color.from`}
*/
export function colorStringToHex(color: string): number | null;
/**
* Internal Helper for {@link Duplicated | `Duplicated`}. A union type of all types that do not have a JSON representation.
*
* @internal
*/
type NonStringifiable = undefined | AnyFunction | AnyConstructor | symbol;
/**
* Internal helper for {@link InnerDuplicated | `InnerDuplicated`}. Maps the properties of `T` to their duplicated types.
*
* @typeParam T - The object type that should have its properties mapped.
* @internal
*/
type MapToInnerDuplicated<T extends object> = { [k in keyof T]: InnerDuplicated<T[k]> };
/**
* Omit properties of `T` which are of type `U`.
*
* @typeParam T - Object type from which properties will be omitted.
* @typeParam U - Properties of this type will be omitted.
* @internal
*/
type OmitOfType<T extends object, U> = { [k in keyof T as T[k] extends U ? never : k]: T[k] };
/**
* Internal helper type for {@link Duplicated | `Duplicated`}. It is the main part of the implementation, which does the recursion.
*
* @typeParam T - Type currently being converted.
* @internal
*/
// prettier-ignore
type InnerDuplicated<T> = T extends { toJSON(): infer U }
? U extends Array<unknown>
? InnerDuplicated<U>
: U extends object
? InnerDuplicated<Omit<U, "toJSON">>
: InnerDuplicated<U>
: T extends NonStringifiable
? undefined
: T extends Array<unknown>
? MapToInnerDuplicated<MapTypeToType<T, NonStringifiable, null>>
: T extends object
? MapToInnerDuplicated<
OmitAssignableFromType<MapTypeToType<T, NonStringifiable, undefined>, undefined> &
Partial<OmitOfType<OmitNotAssignableFromType<MapTypeToType<T, NonStringifiable, undefined>, undefined>, undefined>>
>
: T;
/**
* If T extends `U`, the resulting type is `R`, otherwise it is `T`.
*
* @typeParam T - Original type.
* @typeParam U - Only convert types of this type.
* @typeParam R - Adjust to this type.
* @internal
*/
type TypeToType<T, U, R> = T extends U ? R : T;
/**
* Map the types of properties of `T` to `R` if they are of type `U`.
*
* @typeParam T - Object type that will have its properties' types adjusted.
* @typeParam U - Adjust the types of properties of this type.
* @typeParam R - Type that properties' types will be adjusted to.
* @internal
*/
type MapTypeToType<T, U, R> = { [k in keyof T]: TypeToType<T[k], U, R> };
/**
* Omit properties of `T` which are assignable from `U`.
*
* @typeParam T - Object type that will have its properties omitted.
* @typeParam U - Properties with types that are assignable from this type will be omitted.
* @internal
*/
type OmitAssignableFromType<T extends object, U> = { [k in keyof T as U extends T[k] ? never : k]: T[k] };
/**
* Omit properties of `T` which are not assignable from `U`.
*
* @typeParam T - Object type that will have its properties omitted.
* @typeParam U - Properties with types that are not assignable from this type will be omitted.
* @internal
*/
type OmitNotAssignableFromType<T extends object, U> = { [k in keyof T as U extends T[k] ? k : never]: T[k] };
type OmitByValue<T, ValueType> = { [Key in keyof T as T[Key] extends ValueType ? never : Key]: T[Key] };
type RemoveNever<T> = OmitByValue<T, never>;
type PropWithMinus<K> = K extends string ? `-=${K}` : never;
type DeleteByObjectKeys<T, U, M extends MergeObjectOptions> = M["performDeletions"] extends true
? RemoveNever<{
[K in keyof T]: PropWithMinus<K> extends keyof U ? (U[PropWithMinus<K>] extends null ? never : T[K]) : T[K];
}>
: T;
type RemoveDeletingObjectKeys<T, M extends MergeObjectOptions> = M["performDeletions"] extends true
? RemoveNever<{
[K in keyof T]: K extends string ? (Capitalize<K> extends K ? (T[K] extends null ? never : T[K]) : T[K]) : T[K];
}>
: T;
type MergeObjectProperty<T, U, M extends MergeObjectOptions> =
T extends Array<any>
? U
: T extends Record<string, any>
? U extends Record<string, any>
? M extends { recursive: false }
? U
: MergeObject<
T,
U,
Omit<M, "insertKeys" | "performDeletions"> & {
insertKeys: M["insertValues"];
performDeletions: M["performDeletions"] extends true ? true : false;
}
>
: U
: U;
type UpdateKeys<T, U, M extends MergeObjectOptions> = M extends { overwrite: false }
? T
: { [K in keyof T]: K extends keyof U ? MergeObjectProperty<T[K], U[K], M> : T[K] };
type InsertKeys<T, U> = T & Omit<U, keyof T>;
type UpdateInsert<T, U, M extends MergeObjectOptions> = M extends { insertKeys: false }
? UpdateKeys<T, U, M>
: InsertKeys<UpdateKeys<T, U, M>, U>;
type WithWidenedArrayTypes<T> =
T extends Array<any>
? Array<any>
: T extends Record<string, any>
? { [K in keyof T]: WithWidenedArrayTypes<T[K]> }
: T;