Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(assign): typing Issues and add type-safety tests #158

Closed
wants to merge 13 commits into from
21 changes: 18 additions & 3 deletions src/object/assign.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import { isPlainObject } from 'radashi'

export type GenericObject = Record<string | symbol | number, any>
export type MergeDeep<A, B> = {
[K in keyof A | keyof B]: K extends keyof B
? K extends keyof A
? A[K] extends GenericObject
? B[K] extends GenericObject
? MergeDeep<A[K], B[K]>
: B[K]
: B[K]
: B[K]
: K extends keyof A
? A[K]
: never
}

/**
* Create a copy of the first object, and then merge the second object
* into it recursively. Only plain objects are recursively merged.
Expand All @@ -14,10 +29,10 @@ import { isPlainObject } from 'radashi'
* // => { a: 1, b: 2, c: 3, p: { a: 4, b: 5 } }
* ```
*/
export function assign<X extends Record<string | symbol | number, any>>(
export function assign<X extends GenericObject, Y extends GenericObject>(
initial: X,
override: X,
): X {
override: Y,
): MergeDeep<X, Y> {
if (!initial || !override) {
return initial ?? override ?? {}
}
Expand Down
57 changes: 57 additions & 0 deletions tests/object/assign.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as _ from 'radashi'
import { expectTypeOf } from 'vitest'

describe('assign types', () => {
test('should return merged types', () => {
const obj = _.assign({ a: 1, b: '2', c: true }, { d: 4, e: '5' })
expectTypeOf(obj).toMatchTypeOf<{
a: number
b: string
c: boolean
d: number
e: string
}>()
})

test('should return merged types with nested objects', () => {
const initial = {
a: {
b: 'c',
},
}
const override = {
a: {
c: 'e',
},
d: '2',
}

const obj = _.assign(initial, override)

expectTypeOf(obj).toEqualTypeOf<{
a: { b: string; c: string }
d: string
}>()
})

test('should override types', () => {
const initial = {
a: 1,
b: '2',
c: true,
}
const override = {
a: true,
b: 2,
c: { d: 4 },
}

const obj = _.assign(initial, override)

expectTypeOf(obj).toEqualTypeOf<{
a: boolean
b: number
c: { d: number }
}>()
})
})