Skip to content

Commit

Permalink
feat(types): Partial, PartialNative
Browse files Browse the repository at this point in the history
Signed-off-by: Lexus Drumgold <[email protected]>
  • Loading branch information
unicornware committed Jul 3, 2023
1 parent 4c28575 commit dba9249
Show file tree
Hide file tree
Showing 8 changed files with 338 additions and 5 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"enums",
"get",
"interfaces",
"partial",
"type-definitions",
"type-guards",
"type-programming",
Expand Down
1 change: 1 addition & 0 deletions src/types/__tests__/is-key-optional.spec-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type Indices from '../indices'
import type TestSubject from '../is-key-optional'
import type Nilable from '../nilable'
import type Numeric from '../numeric'
import type Partial from '../partial'
import type PropertyKey from '../property-key'
import type Stringify from '../stringify'

Expand Down
1 change: 1 addition & 0 deletions src/types/__tests__/is-key-required.spec-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type Indices from '../indices'
import type TestSubject from '../is-key-required'
import type Nilable from '../nilable'
import type Numeric from '../numeric'
import type Partial from '../partial'
import type Stringify from '../stringify'

describe('unit-d:types/IsRequiredKey', () => {
Expand Down
1 change: 1 addition & 0 deletions src/types/__tests__/overwrite.spec-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type EmptyObject from '../empty-object'
import type OneOrMany from '../one-or-many'
import type { tag } from '../opaque'
import type TestSubject from '../overwrite'
import type Partial from '../partial'

describe('unit-d:types/Overwrite', () => {
it('should equal T if U is any', () => {
Expand Down
17 changes: 17 additions & 0 deletions src/types/__tests__/partial-native.spec-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* @file Type Tests - PartialNative
* @module tutils/types/tests/unit-d/PartialNative
*/

import type Vehicle from '#fixtures/vehicle'
import type TestSubject from '../partial-native'

describe('unit-d:types/PartialNative', () => {
it('should equal typescript.Partial<T>', () => {
// Arrange
type T = Vehicle

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<Partial<T>>
})
})
307 changes: 307 additions & 0 deletions src/types/__tests__/partial.spec-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
/**
* @file Type Tests - Partial
* @module tutils/types/tests/unit-d/Partial
*/

import type Author from '#fixtures/author.interface'
import type Book from '#fixtures/book.interface'
import type Publisher from '#fixtures/publisher.interface'
import type Vehicle from '#fixtures/vehicle'
import type Fn from '../fn'
import type NIL from '../nil'
import type Nilable from '../nilable'
import type Nullable from '../nullable'
import type { tag } from '../opaque'
import type Optional from '../optional'
import type TestSubject from '../partial'
import type PartialNative from '../partial-native'

describe('unit-d:types/Partial', () => {
it('should equal PartialNative<T> if T is any', () => {
// Arrange
type T = any

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})

it('should equal PartialNative<T> if T is never', () => {
// Arrange
type T = never

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})

it('should equal PartialNative<T> if T is unknown', () => {
// Arrange
type T = unknown

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})

describe('T extends ObjectCurly', () => {
it('should make nested and top-level properties optional', () => {
// Arrange
type T = Omit<Book, 'readers'> & { readers: Set<string> | undefined }

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<{
authors?: Optional<Author>[]
isbn?: PartialNative<T['isbn']>
publisher?: Nullable<{
display_name?: PartialNative<Publisher['display_name']>
email?: PartialNative<Publisher['email']>
name?: PartialNative<Publisher['name']>
}>
readers?: PartialNative<T['readers']>
title?: PartialNative<T['title']>
}>()
})
})

describe('T extends Primitive', () => {
describe('T extends NIL', () => {
it('should equal PartialNative<T>', () => {
// Arrange
type T1 = NIL
type T2 = null
type T3 = undefined

// Expect
expectTypeOf<TestSubject<T1>>().toEqualTypeOf<PartialNative<T1>>()
expectTypeOf<TestSubject<T2>>().toEqualTypeOf<PartialNative<T2>>()
expectTypeOf<TestSubject<T3>>().toEqualTypeOf<PartialNative<T3>>()
})
})

describe('T extends bigint', () => {
it('should make nested and top-level properties optional', () => {
// Arrange
type T = bigint & { data: { readonly id: string } }

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<
PartialNative<
PartialNative<Omit<T, 'data'>> & { data?: { readonly id?: string } }
>
>()
})

describe('bigint extends T', () => {
it('should equal PartialNative<T>', () => {
// Arrange
type T = bigint

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})
})
})

describe('T extends boolean', () => {
it('should make nested and top-level properties optional', () => {
// Arrange
type T = boolean & { data: { readonly id: string } }

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<
PartialNative<
PartialNative<Omit<T, 'data'>> & { data?: { readonly id?: string } }
>
>()
})

describe('boolean extends T', () => {
it('should equal PartialNative<T>', () => {
// Arrange
type T = boolean

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})
})
})

describe('T extends number', () => {
it('should make nested and top-level properties optional', () => {
// Arrange
type T = number & { data: { readonly id: string } }

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<
PartialNative<
PartialNative<Omit<T, 'data'>> & { data?: { readonly id?: string } }
>
>()
})

describe('number extends T', () => {
it('should equal PartialNative<T>', () => {
// Arrange
type T = number

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})
})
})

describe('T extends string', () => {
it('should make nested and top-level properties optional', () => {
// Arrange
type T = string & { data: { readonly id: string } }

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<
PartialNative<
PartialNative<Omit<T, 'data'>> & { data?: { readonly id?: string } }
>
>()
})

describe('string extends T', () => {
it('should equal PartialNative<T>', () => {
// Arrange
type T = string

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})
})
})

describe('T extends symbol', () => {
it('should make nested and top-level properties optional', () => {
// Arrange
type T = symbol & { data: { readonly id: string } }

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<
PartialNative<
PartialNative<Omit<T, 'data'>> & { data?: { readonly id?: string } }
>
>()
})

describe('symbol extends T', () => {
it('should equal PartialNative<T>', () => {
// Arrange
type T = symbol

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})
})
})
})

describe('T extends Readonly<Fn>', () => {
it('should make nested and top-level properties optional', () => {
// Arrange
type T = Readonly<Fn> & { data: { readonly id: string } }

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<
PartialNative<
PartialNative<Omit<T, 'data'>> & { data?: { readonly id?: string } }
>
>()
})

describe('Readonly<Fn> extends T', () => {
it('should equal PartialNative<T>', () => {
// Arrange
type T = Readonly<Fn>

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})
})
})

describe('T extends readonly unknown[]', () => {
describe('IsTuple<T> extends true', () => {
it('should equal PartialNative<T>', () => {
// Arrange
type T = readonly [Vehicle, Nilable<Vehicle>]

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})

describe('R["arrays"] extends true', () => {
it('should recurse into arrays', () => {
// Arrange
type T = readonly [Vehicle, Nilable<Vehicle>]

// Expect
expectTypeOf<TestSubject<T, { arrays: true }>>().toEqualTypeOf<
readonly [PartialNative<Vehicle>?, Nilable<PartialNative<Vehicle>>?]
>()
})
})

describe('T is intersection', () => {
it('should make nested and top-level properties optional', () => {
// Arrange
type T = readonly [Vehicle] & { x: { readonly id: string } }

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<
PartialNative<
PartialNative<Omit<T, 'x'>> & { x?: { readonly id?: string } }
>
>()
})
})
})

describe('number extends Length<T>', () => {
it('should equal PartialNative<T>', () => {
// Arrange
type T = Vehicle[]

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})

describe('R["arrays"] extends true', () => {
it('should recurse into arrays', () => {
// Arrange
type T = Vehicle[]
type R = { arrays: true }
type Expect = Optional<PartialNative<Vehicle>>[]

// Expect
expectTypeOf<TestSubject<T, R>>().toEqualTypeOf<Expect>()
})
})

describe('T is intersection', () => {
it('should make nested and top-level properties optional', () => {
// Arrange
type T = readonly Vehicle[] & { x: { readonly id: string } }

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<
PartialNative<
PartialNative<Omit<T, 'x'>> & { x?: { readonly id?: string } }
>
>()
})
})
})
})

describe('unions', () => {
it('should distribute over unions', () => {
// Arrange
type T = Nilable<Vehicle | Vehicle['vin'] | typeof tag>

// Expect
expectTypeOf<TestSubject<T>>().toEqualTypeOf<PartialNative<T>>()
})
})
})
2 changes: 2 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ export type { default as Optional } from './optional'
export type { default as OrLowercase } from './or-lowercase'
export type { default as OrUppercase } from './or-uppercase'
export type { default as Overwrite } from './overwrite'
export type { default as Partial } from './partial'
export type { default as PartialNative } from './partial-native'
export type { default as Path } from './path'
export type { default as Predicate } from './predicate'
export type { default as Primitive } from './primitive'
Expand Down
Loading

0 comments on commit dba9249

Please sign in to comment.