Skip to content

Commit

Permalink
[dsch] Docs draft
Browse files Browse the repository at this point in the history
  • Loading branch information
DScheglov committed Mar 19, 2021
1 parent 6441b7d commit 2e49bcd
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 4 deletions.
144 changes: 144 additions & 0 deletions docs/1-engine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# ts-cast · Type Checking Engine API

<a name="1-caster-fn"></a>
## 1. CasterFn&lt;T&gt; <sup>`type`</sup>

The named function that accepts `unknown` type value and returns value of
target type `T` or reports about casting error:

```ts
export interface CasterFn<T> {
(value: unknown, context?: string, reportError?: ErrorReporter): T;
name: string;
}

export type ErrorReporter = (message: string, context?: string) => never;
```

### Argumernts

| Parameter | Type | Mandatory / Optional | Descriptions |
| :-------------: | :-------------: | :------------------: | :------------------------------------------------------------------------------------------------------------------------------------ |
| **value** | `unknown` | **mandatory** | The value to be casted |
| **context** | `string` | _optional_ | The Casting Context. It is could be considered as a name of root object to be casted. As instance it could be "SomeApiMethodResponse" |
| **reportError** | `ErrorReporter` | _optional_ | The function accepts an error message and casting context. It could throw an error or return undefined. |

### Returns
- **casted value**: `T`

### Example

```ts
import { CasterFn, ErrorReporter } from 'ts-cast';

const casterFn: CasterFn<number> = function yearOf21stCentury(
value: unknown,
context?: string,
reportError: ErrorReporter = (msg: string) => { throw new TypeError(msg); }
): number {
if (typeof value === 'number' && value > 2000 && value < 2101) {
return value;
}

reportError(
`Current Year is expected${
context ? ` in ${context}` : ''
} but "${value}" received.`,
context,
);
}
```

<a name="2-caster"></a>
## 2. Caster&lt;T&gt; <sup>type</sup>

The extenstion of the `CasterFn<T>` that contains properties and methods to build other types,
including by mapping casted data.

Please note that `CasterFn<T>` doesn't have correspondent methods.

### Type Definition

```ts
export interface Caster<T> extends CasterFn<T> {
optional: Caster<T | undefined>;
nullable: Caster<T | null>;
default(defaltValue: T): Caster<Exclude<T, undefined>>;
restrict(...rules: RuleFn<Exclude<T, null | undefined>>[]): Caster<T>;
map<D>(
transform: (value: Exclude<T, null | undefined>
) => D): Caster<D | Exclude<T, Exclude<T, null | undefined>>>;
validate(value: unknown): ValidationResult<T>;

either<Right, Left>(
leftFactory: (error: TypeError) => Left,
rightFactory:(value: T) => Right,
): CasterFn<Left | Right>;

validation<Valid, Invalid>(
invalidFactory: (errors: ErrorMessage[]) => Invalid,
validFactory: (value: T) => Valid
): CasterFn<Valid | Invalid>;
}
```

### Property `.optional`: `Caster<T | undefined>`

The `.optional` property refers to `Caster` of **optional** type. Optional is considered as _could be undefined_.

**Example**

```ts
const optNumber = number.optional;

optNumber(10); // returns 10
optNumber(undefined); // returns undefined
optNumber(null); // throws a TypeError
```

### Property `.nullable`: `Caster<T | null>`

The `.nullable` property refers to `Caster` of **nullable** type that means the correspondent caster accepts `null` as valid value.

**Example**

```ts
const nullableStr = string.nullable;

nullableStr('Hello World'); // returns "Hello World"
nullableStr(null); // returns null
nullableStr(undefined); // throws a TypeError
```

### Method `.default(value: T)` : `Caster<Exclude<T, undefined>>`

Creates new `Caster` that replaces `undefined` input with `value` specified as argument.

**Arguments**

| Parameter | Type | Mandatory | Description |
| :-------: | :---: | :-------: | :----------------------------------- |
| **value** | `T` | **yes** | The value to replace `undefined` input |

**Returns**
- **caster**: `Caster<Exclude<T, undefined>>`

**Example**

```ts
const someStr = string.default('no-input');

someStr('Hello World'); // returns "Hello World"
someStr(undefined); // returns "no-input"
someStr(null); // throws a TypeError
```

<a name="3-caster-api"></a>
## 3. casterApi&lt;T&gt; <sup>`fn`</sup>

<a name="4-create-caster"></a>
## 4. createCaster&lt;T&gt; <sup>fn</sup>


<a name="5-validate"></a>
## 5. validate&lt;T&gt; <sup>fn</sup>
69 changes: 69 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# ts-cast &middot; API Specification

Runtime type checking for Typescript and JavaScript projects.

## Refernce

1. [Type Checking Engine](./1-engine.md)
1. [CasterFn&lt;T&gt; <sup>`type`</sup>](./1-engine.md#1-caster-fn)
2. [Caster&lt;T&gt; <sup>type</sup>](./1-engine.md#2-caster)
3. [casterApi&lt;T&gt; <sup>`fn`</sup>](./1-engine.md#3-caster-api)
4. [createCaster&lt;T&gt; <sup>fn</sup>](./1-engine.md#4-create-cater)
5. [validate <sup>fn</sup>](./1-engine.md#5-validate)

2. [Primitive Type Casters](./2-types.md#1-primitives)
1. [boolean](./2-types.md$1-1-boolean)
2. [integer](./2-types.md$1-2-integer)
3. [number](./2-types.md$1-3-number)
4. [string](./2-types.md$1-4-string)
5. [text.integer](./2-types.md$1-5-text.integer)
6. [text.number](./2-types.md$1-6-text.number)

3. [Literal Types Casters](./2-types.md#2-literals)
1. [value](./2-types.md#2-1-value)
2. [values](./2-types.md#2-2-values)

4. [Special Types Casters](./2-types.md#3-special)
1. [any](./2-types.md#3-1-any)
2. [nil](./2-types.md#3-2-nil)
3. [undef](./2-types.md#3-3-undef)

5. [Complex Type Casters](./2-types.md#4-complex)
1. [array](./2-types.md#4-1-array)
2. [record](./2-types.md#4-2-record)
3. [struct](./2-types.md#4-3-struct)
4. [tuple](./2-types.md#4-4-tuple)

6. [Recursive Type Casters](./2-types.md)

7. [Type Composition](./3-operations.md)
1. [prod <sup>fn</sup>](./3-operations.md#1-prod)
2. [union <sup>fn</sup>](./3-operations.md#2-union)

8. [Narrowing Types](./4-restrictions.md#1-rules)
1. [Predicate&lt;T&gt; <sup>type</sup>](./4-restrictions.md#1-1-predicate)
2. [RuleFn&lt;T&gt; <sup>type</sup>](./4-restrictions.md#1-2-rulefn)
3. [toBe <sup>fn</sup>](./4-restrictions.md#1-3-tobe)
4. [notToBe <sup>fn</sup>](./4-restrictions.md#1-4-nottobe)
5. [and <sup>fn</sup>](./4-restrictions.md#1-5-and)
6. [or <sup>fn</sup>](./4-restrictions.md#1-6-or)
7. [not <sup>fn</sup>](./4-restrictions.md#1-7-not)

9. [Predicates](./4-restrictions.md#2-predicates)
1. [greaterThen (gt)](./4-restrictions.md#2-1-gt)
2. [lessThen (lt)](./4-restrictions.md#2-2-lt)
3. [notGreaterThen (gte)](./4-restrictions.md#2-3-gte)
4. [notLessThen (lte)](./4-restrictions.md#2-4-lte)
5. [nonEmpty](./4-restrictions.md#2-5-notempty)
6. [longerThen (length.gt)](./4-restrictions.md#2-6-length-gt)
7. [shorterThen (length.lt)](./4-restrictions.md#2-7-length-lt)
8. [notLongerThen (length.lte)](./4-restrictions.md#2-8-length-lte)
9. [notShorterThen (length.gte)](./4-restrictions.md#2-9-length-gte)
10. [matching](./4-restrictions.md#2-10-matching)
11. [notEqual (ne)](./4-restrictions.md#2-11-ne)

10. [Type Guards](./6-type-guards.md)

## How To
1. [Create Custom Types](./custom-types.md)
2. [Cast to Either&lt;\*, T&gt; and Validation&lt;\*, T&gt;](./monadic-caster.md)
2 changes: 1 addition & 1 deletion examples/advanced/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ const myBook = Book({

const book: TBook = myBook;

me.id = UUID('123123123'); // throws TypeError in runtime
// me.id = UUID('123123123'); // throws TypeError in runtime

console.log(JSON.stringify(book, null, 2));
10 changes: 7 additions & 3 deletions examples/advanced/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import v from 'validator';
import {
integer, number, string, struct, tuple, array, union, nil, ref, createCaster, Caster, toBe
} from 'ts-cast';
import { CasterFn, ErrorReporter } from 'ts-cast/lib/engine/types';

class TEmail extends String { private tag: Symbol
};
class TUUID extends String { private tag: Symbol };

const isEmail = (value: unknown): value is TEmail => v.isEmail(value);
const isUUID = (value: unknown): value is TUUID => v.isUUID(value);
const isEmail = (value: unknown): value is TEmail =>
typeof value === 'string' && v.isEmail(value);

const isUUID = (value: unknown): value is TUUID =>
typeof value === 'string' && v.isUUID(value);

export const Email = createCaster('email', isEmail, (email): TEmail => email.toLowerCase());
export const UUID = createCaster('uuid', isUUID);
Expand Down Expand Up @@ -43,4 +47,4 @@ export const Book = struct({


export type TCoords = ReturnType<typeof Coords>;
export type TBook = ReturnType<typeof Book>;
export type TBook = ReturnType<typeof Book>;

0 comments on commit 2e49bcd

Please sign in to comment.