merge-anything
Version:
Merge objects & other types recursively. A simple & small integration.
56 lines (55 loc) • 2.21 kB
TypeScript
import type { Iteration, IterationOf, Next, Pos } from './Iteration.js';
import type { Length, List } from './List.js';
import type { MergeDeep } from './MergeDeep.js';
/**
* Ask TS to re-check that `A1` extends `A2`. And if it fails, `A2` will be enforced anyway. Can
* also be used to add constraints on parameters.
*
* @example
* ;```ts
* type test0 = Cast<'42', string> // '42'
* type test1 = Cast<'42', number> // number
* ```
*
* @param A1 To check against
* @param A2 To cast to
* @returns `A1 | A2`
*/
type Cast<A1, A2> = A1 extends A2 ? A1 : A2;
/**
* Check whether `A1` is part of `A2` or not. The difference with `extends` is that it forces a
* [[Boolean]] return.
*
* @example
* ```ts
* type test0 = Extends<'a' | 'b', 'b'> // Boolean
* type test1 = Extends<'a', 'a' | 'b'> // True
*
* type test2 = Extends<{a: string}, {a: any}> // True
* type test3 = Extends<{a: any}, {a: any, b: any}> // False
*
* type test4 = Extends<never, never> // False
* /// Nothing cannot extend nothing, use `Equals`
* ```
*
* @param A1
* @param A2
* @returns {undefined | undefined} Boolean
*/
type Extends<A1, A2> = [A1] extends [never] ? 0 : A1 extends A2 ? 1 : 0;
type __Assign<O extends Record<string | number | symbol, unknown>, Os extends List<Record<string | number | symbol, unknown>>, I extends Iteration = IterationOf<0>> = Extends<Pos<I>, Length<Os>> extends 1 ? O : __Assign<MergeDeep<O, Os[Pos<I>]>, Os, Next<I>>;
type _Assign<O extends Record<string | number | symbol, unknown>, Os extends List<Record<string | number | symbol, unknown>>> = __Assign<O, Os> extends infer X ? Cast<X, Record<string | number | symbol, unknown>> : never;
/**
* Assign a list of [[Object]] into `O` with [[MergeDeep]]. Merges from right to left, first items
* get overridden by the next ones (last-in overrides).
*
* @example
* ;```ts
* ```
*
* @param O To assign to
* @param Os To assign
* @returns {undefined | undefined} Object
*/
export type Assign<O extends Record<string | number | symbol, unknown>, Os extends List<Record<string | number | symbol, unknown>>> = O extends unknown ? (Os extends unknown ? _Assign<O, Os> : never) : never;
export {};