Skip to content

Commit

Permalink
feat(types): Assign
Browse files Browse the repository at this point in the history
Signed-off-by: Lexus Drumgold <[email protected]>
  • Loading branch information
unicornware committed May 24, 2023
1 parent ac95845 commit 41f9463
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
39 changes: 39 additions & 0 deletions src/types/__tests__/assign.spec-d.ts
Original file line number Diff line number Diff line change
@@ -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<TestSubject<Author, EmptyArray>>().toEqualTypeOf<Author>()
})

it('should equal T if U extends EmptyObject', () => {
expectTypeOf<TestSubject<Author>>().toEqualTypeOf<Author>()
})

it('should merge U into T if U extends ObjectAny', () => {
// Arrange
type U = { email: Lowercase<string> }

// Expect
expectTypeOf<TestSubject<Author, U>>().toEqualTypeOf<Merge<Author, U>>()
})

it('should merge U into T if U extends readonly ObjectAny[]', () => {
// Arrange
type U1 = [{ display_name: string }, { email: Lowercase<string> }]
type U2 = { display_name: string; email: Lowercase<string> }[]
type E1 = Merge<Merge<Author, U1[0]>, U1[1]>
type E2 = Merge<Author, U2[0]>

// Expect
expectTypeOf<TestSubject<Author, U1>>().toEqualTypeOf<E1>()
expectTypeOf<TestSubject<Author, U2>>().toEqualTypeOf<E2>()
})
})
36 changes: 36 additions & 0 deletions src/types/assign.ts
Original file line number Diff line number Diff line change
@@ -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<ObjectAny> = EmptyObject
> = U extends EmptyArray | EmptyObject
? T
: U extends ObjectAny
? Merge<T, U>
: Simplify<
U extends [infer H, ...infer Rest extends readonly ObjectAny[]]
? Assign<H & Omit<T, keyof H>, Rest>
: Assign<T, Head<U>>
>

export type { Assign as default }
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down

0 comments on commit 41f9463

Please sign in to comment.