From 1f0250bd9112e9a8b822a1f50b8f698284a737e7 Mon Sep 17 00:00:00 2001 From: Hugh Rawlinson Date: Wed, 8 Jun 2022 11:43:54 +0200 Subject: [PATCH 1/3] Fix readme typos --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 25c6ef5..9559958 100644 --- a/readme.md +++ b/readme.md @@ -17,7 +17,7 @@ npm i narrowing # yarn add narrowing let a: unknown; if (isXXX(a)) { - // TypeScritp know your type here! + // TypeScript know your type here! } ``` @@ -40,7 +40,7 @@ Basic: Advanced: -These functions help you make advanced type gurads. +These functions help you make advanced type guards. - [has](#has) - [kind](#kind) @@ -87,7 +87,7 @@ function testFunc(a: string, b: number): boolean { } if (isFunction(a)) { - a('11', 1); // no eror + a('11', 1); // no error } if (isInstance(a, Date)) { From 1d89e047b8b05cc8c3f552332d5c838f564b3efd Mon Sep 17 00:00:00 2001 From: Hugh Rawlinson Date: Wed, 8 Jun 2022 12:25:28 +0200 Subject: [PATCH 2/3] Add 'every' type predicate --- readme.md | 34 +++++++++++++++++++ src/index.ts | 9 +++++ test/every.test.ts | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 test/every.test.ts diff --git a/readme.md b/readme.md index 9559958..1f5650e 100644 --- a/readme.md +++ b/readme.md @@ -234,6 +234,39 @@ if (isSuccess(message)) { } ``` +### `every() + +Runtime array type validation. Checks each element of an array. + +```ts +let arr: unknown[] = [1, 2, 3]; +if (every(isNumber)(arr)) { + let typeCheck: number[] = arr; +} +``` + +Works with any narrowing validator, including schemas. + +```ts +interface TestInterface { + id: number; + name: string; +} + +const isTestInterface = schema({ + id: isNumber, + name: isString +}); + +let arr: unknown[] = [{ id: 1, name: 'aaa' }]; + +if (every(isTestInterface)(arr)) { + let typeCheck: TestInterface[] = arr; +} +``` + +``` + ## Version - 1.1.0 @@ -247,3 +280,4 @@ if (isSuccess(message)) { - 1.4.0 - replace ~~`isValidObject()`~~ with `schema()` - add `literal()` +``` diff --git a/src/index.ts b/src/index.ts index cb085de..e21d836 100644 --- a/src/index.ts +++ b/src/index.ts @@ -92,3 +92,12 @@ export function schema(schema: SchemaType): Predicate { return false; }; } + +export function every(predicate: Predicate): Predicate { + return function (value: unknown): value is T[] { + if (Array.isArray(value)) { + return value.every(predicate); + } + return false; + }; +} diff --git a/test/every.test.ts b/test/every.test.ts new file mode 100644 index 0000000..a3732b5 --- /dev/null +++ b/test/every.test.ts @@ -0,0 +1,82 @@ +import { schema, literal, every, isString, isNumber } from '../src/index'; + +test('fails when array contains elements of an unassignable type', () => { + expect(every(isString)([1, 2, 3])).toBe(false); + expect(every(isNumber)([1, '2', 3])).toBe(false); +}); + +test('passes when array contains correct type', () => { + expect(every(isNumber)([1, 2, 3])).toBe(true); + expect(every(isString)(['1', '2', '3'])).toBe(true); +}); + +test('passes when array is empty', () => { + expect(every(isString)([])).toBe(true); + expect(every(isNumber)([])).toBe(true); +}); + +interface TestInterface { + kind: 'test'; + value: { + nestedString: string; + nestedNumber: number; + }; +} + +const isTestInterface = schema({ + kind: literal('test'), + value: schema({ + nestedString: isString, + nestedNumber: isNumber + }) +}); + +test('passes when array contains valid objects', () => { + expect( + every(isTestInterface)([ + { + kind: 'test', + value: { + nestedString: 'string', + nestedNumber: 1 + } + } + ]) + ).toBe(true); +}); + +test('fails when array contains invalid objects', () => { + expect( + every(isTestInterface)([ + { + kind: 'test', + value: { + nested_string: 'string' + } + } + ]) + ).toBe(false); +}); + +every(isString); + +let arr: unknown[] = [1, 2, 3]; +if (every(isNumber)(arr)) { + let typeCheck: number[] = arr; +} + +interface TestInterfaceT { + id: number; + name: string; +} + +const isTestInterfaceT = schema({ + id: isNumber, + name: isString +}); + +let arr2: unknown[] = [{ id: 1, name: 'aaa' }]; + +if (every(isTestInterfaceT)(arr2)) { + let typeCheck: TestInterfaceT[] = arr2; +} From 0ac410dc751da5a49114066b38dd25814887703b Mon Sep 17 00:00:00 2001 From: Hugh Rawlinson Date: Wed, 8 Jun 2022 12:27:33 +0200 Subject: [PATCH 3/3] Add readme example for schema with type argument --- readme.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1f5650e..305414f 100644 --- a/readme.md +++ b/readme.md @@ -234,6 +234,27 @@ if (isSuccess(message)) { } ``` +schema supports a type argument for associating a schema with an existing type + +```ts +interface TestInterface { + id: number; + name: string; +} + +const isTestInterface = schema({ + id: isNumber, + name: isString +}); + +if (isTestInterface(message)) { + // let message: TestInterface + message; +} +``` + +```` + ### `every() Runtime array type validation. Checks each element of an array. @@ -243,7 +264,7 @@ let arr: unknown[] = [1, 2, 3]; if (every(isNumber)(arr)) { let typeCheck: number[] = arr; } -``` +```` Works with any narrowing validator, including schemas.