From 94cbd2a6be90417feb71687532243458e93f0e00 Mon Sep 17 00:00:00 2001 From: Sunny Hirai Date: Sat, 20 Jun 2020 11:52:37 -0700 Subject: [PATCH] Optional properties (#390) --- src/types.ts | 33 ++++++++++++++++++++++++++++++++- test/types/object.ts | 7 ++++++- test/types/optional.ts | 2 +- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/types.ts b/src/types.ts index 3d19e3d6..4c8d83b7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -249,6 +249,37 @@ export function number(): Struct { }) } +/** + * Type helper to Flatten the Union of optional and required properties. + */ + +type Flatten = T extends infer U ? { [K in keyof U]: U[K] } : never + +/** + * Type helper to extract the optional keys of an object + */ + +type OptionalKeys = { + [K in keyof T]: undefined extends T[K] ? K : never +}[keyof T] + +/** + * Type helper to extract the required keys of an object + */ + +type RequiredKeys = { + [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 = Flatten< + { [K in RequiredKeys]: T[K] } & { [K in OptionalKeys]?: T[K] } +> + /** * Validate that an object with specific entry values. */ @@ -258,7 +289,7 @@ export function object>(): Struct< > export function object>( Structs: V -): Struct<{ [K in keyof V]: StructType }, V> +): Struct }>, V> export function object>( Structs?: V ): Struct { diff --git a/test/types/object.ts b/test/types/object.ts index 7f3616ba..16ac9d3d 100644 --- a/test/types/object.ts +++ b/test/types/object.ts @@ -1,4 +1,4 @@ -import { assert, object, number } from '../..' +import { assert, object, optional, number, string } from '../..' import { test } from '..' test>((x) => { @@ -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 +}) diff --git a/test/types/optional.ts b/test/types/optional.ts index 532fafac..d04a77f2 100644 --- a/test/types/optional.ts +++ b/test/types/optional.ts @@ -6,7 +6,7 @@ test((x) => { return x }) -test<{ a: string | undefined }>((x) => { +test<{ a?: string | undefined }>((x) => { assert(x, object({ a: optional(string()) })) return x })