An open API service indexing awesome lists of open source software.

https://github.com/janmalch/ts-code-contracts

Design by contract with TypeScript.
https://github.com/janmalch/ts-code-contracts

hacktoberfest library typescript

Last synced: 9 months ago
JSON representation

Design by contract with TypeScript.

Awesome Lists containing this project

README

          

# ts-code-contracts

[![npm](https://img.shields.io/npm/v/ts-code-contracts)](https://www.npmjs.com/package/ts-code-contracts)
[![Build](https://github.com/JanMalch/ts-code-contracts/workflows/Build/badge.svg)](https://github.com/JanMalch/ts-code-contracts/workflows/Build)
[![coverage](https://img.shields.io/badge/coverage-100%25-success)](https://github.com/JanMalch/ts-code-contracts/blob/master/jest.config.js#L14-L17)
[![minified + gzip](https://badgen.net/bundlephobia/minzip/ts-code-contracts)](https://bundlephobia.com/result?p=ts-code-contracts)

_Design by contract with TypeScript._

## Installation & Usage

```
npm i ts-code-contracts
```

> Requires TypeScript^3.7

You can now import the following functions `from 'ts-code-contracts'`:

- [`requires` for preconditions](#requires)
- [`requiresNonNullish` for null-checks as preconditions](#requiresnonnullish)
- [`checks` for invariants](#checks)
- [`checksNonNullish` for null-checks as invariants](#checksnonnullish)
- [`ensures` for postconditions](#ensures)
- [`ensuresNonNullish` for null-checks as postconditions](#ensuresnonnullish)
- [`asserts` for impossible events](#asserts)
- [`unreachable` for unreachable code branches](#unreachable)
- [`error` to make code more concise](#error)
- [`isDefined` type guard](#isdefined)

Make sure to checkout the examples in the documentation below
or refer to the [test cases](https://github.com/JanMalch/ts-code-contracts/blob/master/index.test.ts#L133-L163)
and [typing assistance](https://github.com/JanMalch/ts-code-contracts/blob/master/index.test-d.ts#L41-L52)!

Contracts are really just handy shorthands to throw an error, if the given condition is not met.
And yet they greatly help the compiler and the readability of your code.

## `requires`

Use it to validate preconditions, like validating arguments.
Throws a `PreconditionError` if the `condition` is `false`.

```ts
function requires(
condition: boolean,
message: string = 'Unmet precondition'
): asserts condition;
```

- `condition` - the condition that should be `true`
- `message` - an optional message for the error

**Example:**

```ts
function myFun(name: string) {
requires(name.length > 10, 'Name must be longer than 10 chars');
}
```

## `requiresNonNullish`

A variation of `requires` that returns the given value unchanged if it is not `null` or `undefined`.
Throws a `PreconditionError` otherwise.

```ts
function requiresNonNullish(
value: T,
message = 'Value must not be null or undefined'
): NonNullable;
```

- `value` - the value that should not be `null` or `undefined`
- `message` - an optional message for the error

**Example:**

```ts
function myFun(name: string | null) {
const nameNonNull = requiresNonNullish(name, 'Name must be defined');
nameNonNull.toUpperCase(); // no compiler error!
}
```

## `checks`

Use it to check for an illegal state.
Throws a `IllegalStateError` if the `condition` is `false`.

```ts
function checks(
condition: boolean,
message = 'Callee invariant violation'
): asserts condition;
```

- `condition` - the condition that should be `true`
- `message` - an optional message for the error

**Example:**

```ts
class Socket {
private isOpen = false;
send(data: Data) {
check(this.isOpen, 'Socket must be open');
}
open() {
this.isOpen = true;
}
}
```

## `checksNonNullish`

A variation of `checks` that returns the given value unchanged if it is not `null` or `undefined`.
Throws a `IllegalStateError` otherwise.

```ts
function checksNonNullish(
value: T,
message = 'Value must not be null or undefined'
): NonNullable;
```

- `value` - the value that should not be `null` or `undefined`
- `message` - an optional message for the error

**Example:**

```ts
class Socket {
data: Data | null = null;
send() {
const validData = checksNonNullish(this.data, 'Data must be available');
validData.send(); // no compiler error!
}
}
```

## `ensures`

Use it to verify that your code behaved correctly.
Throws a `PostconditionError` if the `condition` is `false`.

```ts
function ensures(
condition: boolean,
message = 'Unmet postcondition'
): asserts condition;
```

- `condition` - the condition that should be `true`
- `message` - an optional message for the error

**Example:**

```ts
function myFun() {
createPerson({ id: 0, name: 'John' });
const entity = findById(0); // returns null if not present
return ensures(isDefined(entity), 'Failed to persist entity');
}
```

## `ensuresNonNullish`

A variation of `ensures` that returns the given value unchanged if it is not `null` or `undefined`.
Throws a `PostconditionError` otherwise.

```ts
function ensuresNonNullish(
value: T,
message = 'Value must not be null or undefined'
): NonNullable;
```

- `value` - the value that should not be `null` or `undefined`
- `message` - an optional message for the error

**Example:**

```ts
function myFun(): Person {
createPerson({ id: 0, name: 'John' });
const entity = findById(0); // returns null if not present
return ensuresNonNullish(entity, 'Failed to persist entity');
}
```

## `asserts`

Clarify that you think that the given condition is impossible to happen.
Throws a `AssertionError` if the `condition` is `false`.

```ts
asserts(
condition: boolean,
message?: string
): asserts condition;
```

- `condition` - the condition that should be `true`
- `message` - an optional message for the error

## `unreachable`

Asserts that a code branch is unreachable. If it is, the compiler will throw a type error.
If this function is reached at runtime, an error will be thrown.

```ts
function unreachable(
value: never,
message = 'Reached an unreachable case'
): never;
```

- `value` - a value
- `message` - an optional message for the error

**Example:**

```ts
function myFun(foo: MyEnum): string {
switch (foo) {
case MyEnum.A:
return 'a';
case MyEnum.B:
return 'b';
// no compiler error if MyEnum only has A and B
default:
unreachable(foo);
}
}
```

## `error`

This function will always throw an error.
It helps keeping code easy to read and come in handy when assigning values with a ternary operator or the null-safe operators.

```ts
function error(message?: string): never;
function error(
errorType: new (...args: any[]) => Error,
message?: string
): never;
```

- `errorType` - an error class, defaults to `IllegalStateError`
- `message` - an optional message for the error

**Example:**

```ts
function myFun(foo: string | null) {
const bar = foo ?? error(PreconditionError, 'Argument may not be null');
const result = bar.length > 0 ? 'OK' : error('Something went wrong!');
}
```

## `isDefined`

A type guard, to check that a value is not `null` or `undefined`.
Make sure to use [`strictNullChecks`](https://basarat.gitbook.io/typescript/intro/strictnullchecks).

```ts
function isDefined(value: T): value is NonNullable;
```

- `value` - the value to test

**Example:**

```ts
const x: string | null = 'Hello';
if (isDefined(x)) {
x.toLowerCase(); // no compiler error!
}
```

## Errors

The following error classes are included:

- `PreconditionError` → An error thrown, if a precondition for a function or method is not met.
- `IllegalStateError` → An error thrown, if an object is an illegal state.
- `PostconditionError` → An error thrown, if a function or method could not fulfil a postcondition.
- `AssertionError` → An error thrown, if an assertion has failed.