From ba66c895c7e52263268d179c142088f3e245a033 Mon Sep 17 00:00:00 2001 From: Piotrek Witek Date: Sat, 9 Nov 2019 12:43:23 +0100 Subject: [PATCH] Improve docs & tests (#125) * Updated tests and documentation for aliases and guards * Fixed docs issues and improved organization --- README.md | 101 +++++++++--------- .../aliases-and-guards.spec.ts.snap | 8 +- src/aliases-and-guards.spec.snap.ts | 40 +++---- src/aliases-and-guards.spec.ts | 36 +++---- 4 files changed, 87 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index 994c6b3..c773f3f 100644 --- a/README.md +++ b/README.md @@ -82,15 +82,12 @@ We are open for contributions. If you're planning to contribute please make sure # Table of Contents -## Aliases +## Aliases & Type Guards * [`Primitive`](#primitive) +* [`isPrimitive`](#isprimitive) * [`Falsy`](#falsy) - -## Type Guards - -* ['isPrimitive'](#isprimitive) -* ['isFalsy'](#isfalsy) +* [`isFalsy`](#isfalsy) ## Union operators @@ -107,11 +104,11 @@ We are open for contributions. If you're planning to contribute please make sure * [`FunctionKeys`](#functionkeyst) * [`NonFunctionKeys`](#nonfunctionkeyst) -* [`ReadonlyKeys`](#readonlykeyst) * [`MutableKeys`](#mutablekeyst) +* [`ReadonlyKeys`](#readonlykeyst) * [`RequiredKeys`](#requiredkeyst) -* [`Optional`](#optionalt-k) * [`OptionalKeys`](#optionalkeyst) +* [`Optional`](#optionalt-k) * [`Partial`](#partialt) _(built-in)_ * [`DeepPartial`](#deeppartialt) * [`Required`](#requiredt-k) @@ -166,15 +163,6 @@ Type representing primitive types in JavaScript, and thus TypeScript: `string | You can test for singular of these types with [`typeof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) -[⇧ back to top](#table-of-contents) - -### `Falsy` - -Type representing falsy values in TypeScript: `false | "" | 0 | null | undefined` -> Except `NaN` which cannot be represented as a type literal - -[⇧ back to top](#table-of-contents) - ### `isPrimitive` This is a [TypeScript Typeguard](https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types) for the [`Primitive`](#primitive) type. @@ -195,9 +183,27 @@ const consumer = (param: Primitive[] | Primitive): string => { }; ``` +[⇧ back to top](#table-of-contents) + +### `Falsy` + +Type representing falsy values in TypeScript: `false | "" | 0 | null | undefined` +> Except `NaN` which cannot be represented as a type literal + ### `isFalsy` -As `isPrimitive` but for the type [`Falsy`](#falsy). +```ts +const consumer = (param: Falsy | string): string => { + if (isFalsy(param)) { + // typeof param === Falsy + return String(param) + ' was Falsy'; + } + // typeof param === string + return param.toString(); +}; +``` + +[⇧ back to top](#table-of-contents) ### `SetIntersection` (same as Extract) @@ -301,7 +307,7 @@ import { FunctionKeys } from 'utility-types'; type MixedProps = { name: string; setName: (name: string) => void }; // Expect: "setName" -type FunctionKeysProps = FunctionKeys; +type Keys = FunctionKeys; ``` [⇧ back to top](#table-of-contents) @@ -318,43 +324,43 @@ import { NonFunctionKeys } from 'utility-types'; type MixedProps = { name: string; setName: (name: string) => void }; // Expect: "name" -type NonFunctionKeysProps = NonFunctionKeys; +type Keys = NonFunctionKeys; ``` [⇧ back to top](#table-of-contents) -### `ReadonlyKeys` +### `MutableKeys` -Get union type of keys that are readonly in object type `T` +Get union type of keys that are mutable (not readonly) in object type `T` + +Alias: `WritableKeys` **Usage:** ```ts -import { ReadonlyKeys } from 'utility-types'; +import { MutableKeys } from 'utility-types'; type Props = { readonly foo: string; bar: number }; -// Expect: "foo" -type ReadonlyProps = ReadonlyKeys; +// Expect: "bar" +type Keys = MutableKeys; ``` [⇧ back to top](#table-of-contents) -### `MutableKeys` - -Get union type of keys that are mutable (not readonly) in object type `T` +### `ReadonlyKeys` -Alias: `WritableKeys` +Get union type of keys that are readonly in object type `T` **Usage:** ```ts -import { MutableKeys } from 'utility-types'; +import { ReadonlyKeys } from 'utility-types'; type Props = { readonly foo: string; bar: number }; -// Expect: "bar" -type MutableProps = MutableKeys; +// Expect: "foo" +type Keys = ReadonlyKeys; ``` [⇧ back to top](#table-of-contents) @@ -371,48 +377,47 @@ import { RequiredKeys } from 'utility-types'; type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; }; // Expect: "req" | "reqUndef" -type RequiredProps = ReadonlyKeys; +type Keys = RequiredKeys; ``` [⇧ back to top](#table-of-contents) -### `Optional` +### `OptionalKeys` -From `T` make a set of properties by key `K` become optional +Get union type of keys that are optional in object type `T` **Usage:** ```ts -import { Optional } from 'utility-types'; +import { OptionalKeys } from 'utility-types'; -type Props = { name: string; age: number; visible: boolean; }; +type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; }; -// Expect: { name?: string; age?: number; visible?: boolean; } -type Props = Optional -// Expect: { name: string; age?: number; visible?: boolean; } -type Props = Optional; +// Expect: "opt" | "optUndef" +type Keys = OptionalKeys; ``` [⇧ back to top](#table-of-contents) -### `OptionalKeys` +### `Optional` -Get union type of keys that are optional in object type `T` +From `T` make a set of properties by key `K` become optional **Usage:** ```ts -import { OptionalKeys } from 'utility-types'; +import { Optional } from 'utility-types'; -type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; }; +type Props = { name: string; age: number; visible: boolean; }; -// Expect: "opt" | "optUndef" -type OptionalProps = OptionalKeys; +// Expect: { name?: string; age?: number; visible?: boolean; } +type Props = Optional +// Expect: { name: string; age?: number; visible?: boolean; } +type Props = Optional; ``` [⇧ back to top](#table-of-contents) ---- ### `Pick` _(built-in)_ diff --git a/src/__snapshots__/aliases-and-guards.spec.ts.snap b/src/__snapshots__/aliases-and-guards.spec.ts.snap index 10c5a0e..0371693 100644 --- a/src/__snapshots__/aliases-and-guards.spec.ts.snap +++ b/src/__snapshots__/aliases-and-guards.spec.ts.snap @@ -4,13 +4,9 @@ exports[`Falsy testType() (type) should match snapshot 1`] = `"Falsy"`; exports[`Primitive testType() (type) should match snapshot 1`] = `"Primitive"`; -exports[`isFalsy - test falsy values val (type) should match snapshot 1`] = `"Falsy"`; +exports[`isFalsy param (type) should match snapshot 1`] = `"false | 0 | null | undefined"`; -exports[`isFalsy - test falsy values val (type) should match snapshot 2`] = `"unknown"`; - -exports[`isFalsy - test truthy values val (type) should match snapshot 1`] = `"Falsy"`; - -exports[`isFalsy - test truthy values val (type) should match snapshot 2`] = `"unknown"`; +exports[`isFalsy param (type) should match snapshot 2`] = `"string"`; exports[`isPrimitive param (type) should match snapshot 1`] = `"Primitive"`; diff --git a/src/aliases-and-guards.spec.snap.ts b/src/aliases-and-guards.spec.snap.ts index 97b323b..386ecb0 100644 --- a/src/aliases-and-guards.spec.snap.ts +++ b/src/aliases-and-guards.spec.snap.ts @@ -30,38 +30,32 @@ it('narrows to correct type', () => { testType(); } -// @dts-jest:group isFalsy - test falsy values -it('returns true for falsy and narrows type', () => { - const falsyTestVals: unknown[] = ['', null, undefined, false, 0]; - - falsyTestVals.forEach(val => { - if (isFalsy(val)) { - // @dts-jest:pass:snap -> Falsy - val; +// @dts-jest:group isFalsy +it('narrows to correct type', () => { + const consumer = (param: Falsy | string): string => { + if (isFalsy(param)) { + // @dts-jest:pass:snap -> false | 0 | null | undefined + param; + return String(param) + ' was Falsy'; } - // @dts-jest:pass:snap -> unknown - val; - }); + // @dts-jest:pass:snap -> string + param; + return param.toString(); + }; +}); - const testResults = falsyTestVals.map(isFalsy); +// @dts-jest:group isFalsy - test falsy values +it('returns true for falsy', () => { + const falsyTestVals: unknown[] = [false, '', 0, null, undefined]; + const testResults = falsyTestVals.map(isFalsy); testResults.forEach(val => expect(val).toBe(true)); }); // @dts-jest:group isFalsy - test truthy values -it('returns false for truthy and narrows type', () => { +it('returns false for truthy', () => { const truthyTestVals: unknown[] = [' ', true, {}, []]; - truthyTestVals.forEach(val => { - if (isFalsy(val)) { - // @dts-jest:pass:snap -> Falsy - val; - } - // @dts-jest:pass:snap -> unknown - val; - }); - const testResults = truthyTestVals.map(isFalsy); - testResults.forEach(val => expect(val).toBe(false)); }); diff --git a/src/aliases-and-guards.spec.ts b/src/aliases-and-guards.spec.ts index a691d37..d266203 100644 --- a/src/aliases-and-guards.spec.ts +++ b/src/aliases-and-guards.spec.ts @@ -30,38 +30,32 @@ it('narrows to correct type', () => { testType(); } -// @dts-jest:group isFalsy - test falsy values -it('returns true for falsy and narrows type', () => { - const falsyTestVals: unknown[] = ['', null, undefined, false, 0]; - - falsyTestVals.forEach(val => { - if (isFalsy(val)) { +// @dts-jest:group isFalsy +it('narrows to correct type', () => { + const consumer = (param: Falsy | string): string => { + if (isFalsy(param)) { // @dts-jest:pass:snap - val; + param; + return String(param) + ' was Falsy'; } // @dts-jest:pass:snap - val; - }); + param; + return param.toString(); + }; +}); - const testResults = falsyTestVals.map(isFalsy); +// @dts-jest:group isFalsy - test falsy values +it('returns true for falsy', () => { + const falsyTestVals: unknown[] = [false, '', 0, null, undefined]; + const testResults = falsyTestVals.map(isFalsy); testResults.forEach(val => expect(val).toBe(true)); }); // @dts-jest:group isFalsy - test truthy values -it('returns false for truthy and narrows type', () => { +it('returns false for truthy', () => { const truthyTestVals: unknown[] = [' ', true, {}, []]; - truthyTestVals.forEach(val => { - if (isFalsy(val)) { - // @dts-jest:pass:snap - val; - } - // @dts-jest:pass:snap - val; - }); - const testResults = truthyTestVals.map(isFalsy); - testResults.forEach(val => expect(val).toBe(false)); });