From 12b25b44f31807c550d0bf6fbe209a2ab5d729b7 Mon Sep 17 00:00:00 2001 From: Sunny Hirai Date: Fri, 19 Jun 2020 18:19:04 -0700 Subject: [PATCH 1/2] Add watch:types to enable automatic compilation of types --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 8375b9e1..36a24dd2 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,8 @@ "test": "yarn build:types && yarn test:types && yarn build:cjs && yarn test:mocha", "test:mocha": "mocha --require ./test/register.cjs --require source-map-support/register ./test/index.ts", "test:types": "tsc --noEmit && tsc --project ./test/tsconfig.json --noEmit", - "watch": "yarn build:cjs --watch" + "watch": "yarn build:cjs --watch", + "watch:types": "yarn build:types --watch" }, "keywords": [ "api", From 2373d1a22b6e894d1a2b0b81963f595dd69422e0 Mon Sep 17 00:00:00 2001 From: Sunny Hirai Date: Fri, 19 Jun 2020 19:18:27 -0700 Subject: [PATCH 2/2] Create optional properties if value can be undefined --- 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 })