diff --git a/src/types/__tests__/assign.spec-d.ts b/src/types/__tests__/assign.spec-d.ts new file mode 100644 index 00000000..1a0b3121 --- /dev/null +++ b/src/types/__tests__/assign.spec-d.ts @@ -0,0 +1,39 @@ +/** + * @file Type Tests - Assign + * @module tutils/types/tests/unit-d/Assign + */ + +import type Author from '#fixtures/author.interface' +import type TestSubject from '../assign' +import type EmptyArray from '../empty-array' +import type Merge from '../merge' + +describe('unit-d:types/Assign', () => { + it('should equal T if U extends EmptyArray', () => { + expectTypeOf>().toEqualTypeOf() + }) + + it('should equal T if U extends EmptyObject', () => { + expectTypeOf>().toEqualTypeOf() + }) + + it('should merge U into T if U extends ObjectAny', () => { + // Arrange + type U = { email: Lowercase } + + // Expect + expectTypeOf>().toEqualTypeOf>() + }) + + it('should merge U into T if U extends readonly ObjectAny[]', () => { + // Arrange + type U1 = [{ display_name: string }, { email: Lowercase }] + type U2 = { display_name: string; email: Lowercase }[] + type E1 = Merge, U1[1]> + type E2 = Merge + + // Expect + expectTypeOf>().toEqualTypeOf() + expectTypeOf>().toEqualTypeOf() + }) +}) diff --git a/src/types/assign.ts b/src/types/assign.ts new file mode 100644 index 00000000..4f12373d --- /dev/null +++ b/src/types/assign.ts @@ -0,0 +1,36 @@ +/** + * @file Type Definitions - Assign + * @module tutils/types/Assign + */ + +import type EmptyArray from './empty-array' +import type EmptyObject from './empty-object' +import type Head from './head' +import type Merge from './merge' +import type ObjectAny from './object-any' +import type OneOrMany from './one-or-many' +import type Simplify from './simplify' + +/** + * Merges one or more source objects into target object `T`. + * + * Source objects are applied from left to right. Properties of rightmost + * sources override those of leftmost sources. + * + * @template T - Target object + * @template U - Source object or source object array + */ +type Assign< + T extends ObjectAny, + U extends OneOrMany = EmptyObject +> = U extends EmptyArray | EmptyObject + ? T + : U extends ObjectAny + ? Merge + : Simplify< + U extends [infer H, ...infer Rest extends readonly ObjectAny[]] + ? Assign, Rest> + : Assign> + > + +export type { Assign as default } diff --git a/src/types/index.ts b/src/types/index.ts index bce224c4..99e2094e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -3,6 +3,7 @@ * @module tutils/types */ +export type { default as Assign } from './assign' export type { default as At } from './at' export type { default as Booleanish } from './booleanish' export type { default as BuiltIn } from './built-in'