Skip to content

Commit

Permalink
Improve docs & tests (#125)
Browse files Browse the repository at this point in the history
* Updated tests and documentation for aliases and guards

* Fixed docs issues and improved organization
  • Loading branch information
piotrwitek authored Nov 9, 2019
1 parent 2ae7412 commit ba66c89
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 98 deletions.
101 changes: 53 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -107,11 +104,11 @@ We are open for contributions. If you're planning to contribute please make sure

* [`FunctionKeys<T>`](#functionkeyst)
* [`NonFunctionKeys<T>`](#nonfunctionkeyst)
* [`ReadonlyKeys<T>`](#readonlykeyst)
* [`MutableKeys<T>`](#mutablekeyst)
* [`ReadonlyKeys<T>`](#readonlykeyst)
* [`RequiredKeys<T>`](#requiredkeyst)
* [`Optional<T, K>`](#optionalt-k)
* [`OptionalKeys<T>`](#optionalkeyst)
* [`Optional<T, K>`](#optionalt-k)
* [`Partial<T>`](#partialt) _(built-in)_
* [`DeepPartial<T>`](#deeppartialt)
* [`Required<T, K>`](#requiredt-k)
Expand Down Expand Up @@ -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.
Expand All @@ -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<A, B>` (same as Extract)

Expand Down Expand Up @@ -301,7 +307,7 @@ import { FunctionKeys } from 'utility-types';
type MixedProps = { name: string; setName: (name: string) => void };

// Expect: "setName"
type FunctionKeysProps = FunctionKeys<MixedProps>;
type Keys = FunctionKeys<MixedProps>;
```

[⇧ back to top](#table-of-contents)
Expand All @@ -318,43 +324,43 @@ import { NonFunctionKeys } from 'utility-types';
type MixedProps = { name: string; setName: (name: string) => void };

// Expect: "name"
type NonFunctionKeysProps = NonFunctionKeys<MixedProps>;
type Keys = NonFunctionKeys<MixedProps>;
```

[⇧ back to top](#table-of-contents)

### `ReadonlyKeys<T>`
### `MutableKeys<T>`

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<T>`

**Usage:**

```ts
import { ReadonlyKeys } from 'utility-types';
import { MutableKeys } from 'utility-types';

type Props = { readonly foo: string; bar: number };

// Expect: "foo"
type ReadonlyProps = ReadonlyKeys<Props>;
// Expect: "bar"
type Keys = MutableKeys<Props>;
```

[⇧ back to top](#table-of-contents)

### `MutableKeys<T>`

Get union type of keys that are mutable (not readonly) in object type `T`
### `ReadonlyKeys<T>`

Alias: `WritableKeys<T>`
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<Props>;
// Expect: "foo"
type Keys = ReadonlyKeys<Props>;
```

[⇧ back to top](#table-of-contents)
Expand All @@ -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<Props>;
type Keys = RequiredKeys<Props>;
```

[⇧ back to top](#table-of-contents)

### `Optional<T, K>`
### `OptionalKeys<T>`

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<Props>
// Expect: { name: string; age?: number; visible?: boolean; }
type Props = Optional<Props, 'age' | 'visible'>;
// Expect: "opt" | "optUndef"
type Keys = OptionalKeys<Props>;
```

[⇧ back to top](#table-of-contents)

### `OptionalKeys<T>`
### `Optional<T, K>`

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<Props>;
// Expect: { name?: string; age?: number; visible?: boolean; }
type Props = Optional<Props>
// Expect: { name: string; age?: number; visible?: boolean; }
type Props = Optional<Props, 'age' | 'visible'>;
```

[⇧ back to top](#table-of-contents)

---

### `Pick<T, K>` _(built-in)_

Expand Down
8 changes: 2 additions & 6 deletions src/__snapshots__/aliases-and-guards.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@ exports[`Falsy testType<Falsy>() (type) should match snapshot 1`] = `"Falsy"`;
exports[`Primitive testType<Primitive>() (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"`;
Expand Down
40 changes: 17 additions & 23 deletions src/aliases-and-guards.spec.snap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,38 +30,32 @@ it('narrows to correct type', () => {
testType<Falsy>();
}

// @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));
});
36 changes: 15 additions & 21 deletions src/aliases-and-guards.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,38 +30,32 @@ it('narrows to correct type', () => {
testType<Falsy>();
}

// @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));
});

0 comments on commit ba66c89

Please sign in to comment.