Skip to content

Commit

Permalink
Optional properties (#390)
Browse files Browse the repository at this point in the history
  • Loading branch information
thesunny authored Jun 20, 2020
1 parent 57230d3 commit 94cbd2a
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 3 deletions.
33 changes: 32 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,37 @@ export function number(): Struct<number> {
})
}

/**
* Type helper to Flatten the Union of optional and required properties.
*/

type Flatten<T> = T extends infer U ? { [K in keyof U]: U[K] } : never

/**
* Type helper to extract the optional keys of an object
*/

type OptionalKeys<T> = {
[K in keyof T]: undefined extends T[K] ? K : never
}[keyof T]

/**
* Type helper to extract the required keys of an object
*/

type RequiredKeys<T> = {
[K in keyof T]: undefined extends T[K] ? never : K
}[keyof T]

/**
* Type helper to create optional properties when the property value can be
* undefined (ie. when `optional()` is used to define a type)
*/

type OptionalizeObject<T> = Flatten<
{ [K in RequiredKeys<T>]: T[K] } & { [K in OptionalKeys<T>]?: T[K] }
>

/**
* Validate that an object with specific entry values.
*/
Expand All @@ -258,7 +289,7 @@ export function object<V extends StructRecord<any>>(): Struct<
>
export function object<V extends StructRecord<any>>(
Structs: V
): Struct<{ [K in keyof V]: StructType<V[K]> }, V>
): Struct<OptionalizeObject<{ [K in keyof V]: StructType<V[K]> }>, V>
export function object<V extends StructRecord<any>>(
Structs?: V
): Struct<any, any> {
Expand Down
7 changes: 6 additions & 1 deletion test/types/object.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert, object, number } from '../..'
import { assert, object, optional, number, string } from '../..'
import { test } from '..'

test<Record<string, unknown>>((x) => {
Expand All @@ -10,3 +10,8 @@ test<{ a: number }>((x) => {
assert(x, object({ a: number() }))
return x
})

test<{ a?: number }>((x) => {
assert(x, object({ a: optional(number()) }))
return x
})
2 changes: 1 addition & 1 deletion test/types/optional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ test<string | undefined>((x) => {
return x
})

test<{ a: string | undefined }>((x) => {
test<{ a?: string | undefined }>((x) => {
assert(x, object({ a: optional(string()) }))
return x
})

0 comments on commit 94cbd2a

Please sign in to comment.