# typecraft

> library for crafting types and casting type inhabitants

Latest version **1.1.0** (published 2022-09-15) · MIT license · 0 weekly downloads

## Install

```sh
npm install typecraft
pnpm add typecraft
yarn add typecraft
bun add typecraft
```

## Health

**Score 30/100 (F)** — status: abandoned.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.1.0 |
| Published | 2022-09-15 |
| First published | 2022-09-09 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 67.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 0 |
| Author | Aadit M Shah |
| Maintainers | aaditmshah |
| Keywords | cast, casting, check, checking, craft, crafting, safe, safety, type, type-cast, type-casting, type-check, type-checking, type-craft, type-crafting, type-safe, type-safety, typecast, typecasting, typecheck, typechecking, typecraft, typecrafting, types, typesafe, typesafety, typescript |

## Links

- npm: https://www.npmjs.com/package/typecraft
- Repository: https://github.com/aaditmshah/typecraft
- Issues: https://github.com/aaditmshah/typecraft/issues
- Funding: https://aadit.codes/sponsor
- npm.io page: https://npm.io/package/typecraft

## Alternatives

- [@openai/codex-sdk](https://npm.io/package/@openai/codex-sdk.md) — 731.4K weekly downloads
- [babel-plugin-transform-react-jsx](https://npm.io/package/babel-plugin-transform-react-jsx.md) — 565.0K weekly downloads
- [babel-helper-remove-or-void](https://npm.io/package/babel-helper-remove-or-void.md) — 508.5K weekly downloads
- [@pnpm/store-controller-types](https://npm.io/package/@pnpm/store-controller-types.md) — 186.9K weekly downloads
- [react-native-signature-canvas](https://npm.io/package/react-native-signature-canvas.md) — 155.6K weekly downloads

## Recent versions

- 1.1.0 (latest) — 2022-09-15
- 1.2.0-alpha.3 (alpha) — 2022-09-23
- 1.2.0-alpha.2 — 2022-09-19
- 1.2.0-alpha.1 — 2022-09-18
- 1.1.1-alpha.1 — 2022-09-17
- 1.0.0 — 2022-09-13
- 0.1.1 — 2022-09-10
- 0.1.0 — 2022-09-09

## README

# Typecraft

![GitHub Workflow Status](https://img.shields.io/github/workflow/status/aaditmshah/typecraft/Continuous%20Integration?logo=github)
[![GitHub license](https://img.shields.io/github/license/aaditmshah/typecraft)](https://github.com/aaditmshah/typecraft/blob/main/LICENSE)
![npm](https://img.shields.io/npm/v/typecraft?logo=npm)
[![semantic-release: gitmoji](https://img.shields.io/badge/semantic--release-gitmoji-E10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)
[![Twitter](https://img.shields.io/twitter/url?url=https%3A%2F%2Fgithub.com%2Faaditmshah%2Ftypecraft)](https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Fgithub.com%2Faaditmshah%2Ftypecraft)

Typecraft is a library for performing type-level magic. For example, you can use it to safely typecast values.

```typescript
import type { Type } from "typecraft";
import { string, number, boolean, object, optional, cast } from "typecraft";

interface Person {
  name: string;
  age: number;
  alive?: boolean | undefined;
}

// Craft a new person type.
const person: Type<Person> = object({
  name: string,
  age: number,
  alive: optional(boolean)
});

/**
 * Create a new magic spell, a.k.a. function,
 * to typecast unknown values to person type.
 */
const personify = cast(person);

const fetchPerson = async (url: string): Promise<Person> => {
  const response = await fetch(url);
  const data: unknown = await response.json();
  const result = personify(data); // Cast the personify spell.
  switch (result.status) {
    case "success":
      return result.value; // The result contains the person value.
    case "failure":
      console.error(result); // The result has debugging information.
      throw new TypeError("Could not parse the response data.");
    // no default
  }
};
```

Typecasting a value produces an entirely new value. It follows the principle of ["parse, don't validate"](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/). Hence, typecasting is more powerful than simple data validation. For example, because `Type` is functorial you can [transfigure](https://harrypotter.fandom.com/wiki/Transfiguration) a value while typecasting it using the `map` function. This is very useful when you get data from an API in one format, but you want to transform it into another format for ease of use.

```typescript
import type { Type } from "typecraft";
import { string, number, boolean, object, optional, map } from "typecraft";

interface Person {
  name: string;
  age: number;
  alive: boolean; // The alive property is required.
}

const person: Type<Person> = map(
  // Provide a default value for alive.
  ({ name, age, alive = true }) => ({
    name,
    age,
    alive
  }),
  object({
    name: string,
    age: number,
    alive: optional(boolean)
  })
);
```

## API

### `Type`

```typescript
import type { Type } from "typecraft";
import { string, array } from "typecraft";

const strings: Type<string> = array(string);
```

`Type<A>` is a description of `A`. Think of it as a recipe to create a value of type `A`. It's the main data type of typecraft. All type combinators return a `Type`.

### `Typedef`

```typescript
import type { Typedef } from "typecraft";
import { string, array } from "typecraft";

// type Strings = string[];
type Strings = Typedef<typeof strings>;
const strings = array(string);
```

`Typedef<Type<A>>` returns the type `A`. This is useful when you want to get the type described by a type combinator.

### `unknown`

```typescript
declare const unknown: Type<unknown>;
```

```typescript
import { unknown } from "typecraft";
```

The `unknown` type combinator describes unknown values. Typecasting `unknown` returns a function which always succeeds. The resultant value is the same as the input.

### `never`

```typescript
declare const never: Type<never>;
```

```typescript
import { never } from "typecraft";
```

The `never` type combinator describes values which don't exist. Typecasting `never` returns a functions which always fails.

### `string`

```typescript
declare const string: Type<string>;
```

```typescript
import { string } from "typecraft";
```

The `string` type combinator describes strings. Typecasting `string` returns a function which only succeeds if the input is a string.

### `number`

```typescript
declare const number: Type<number>;
```

```typescript
import { number } from "typecraft";
```

The `number` type combinator describes numbers. Typecasting `number` returns a function which only succeeds if the input is a number.

### `bigint`

```typescript
declare const bigint: Type<bigint>;
```

```typescript
import { bigint } from "typecraft";
```

The `bigint` type combinator describes bigints. Typecasting `bigint` returns a function which only succeeds if the input is a bigint.

### `boolean`

```typescript
declare const boolean: Type<boolean>;
```

```typescript
import { boolean } from "typecraft";
```

The `boolean` type combinator describes booleans. Typecasting `boolean` returns a function which only succeeds if the input is a boolean.

### `symbol`

```typescript
declare const symbol: Type<symbol>;
```

```typescript
import { symbol } from "typecraft";
```

The `symbol` type combinator describes symbols. Typecasting `symbol` returns a function which only succeeds if the input is a symbol.

### `primitive`

```typescript
declare interface Primitives {
  string: string;
  number: number;
  bigint: bigint;
  boolean: boolean;
  symbol: symbol;
  null: null;
  undefined: undefined;
}

declare const primitive: <A extends keyof Primitives>(
  type: A
) => Type<Primitives[A]>;
```

```typescript
import type { Type } from "typecraft";
import { primitive } from "typecraft";

const nil: Type<null> = primitive("null");
const undef: Type<undefined> = primitive("undefined");
```

The `primitive` type combinator describes primitive values of a certain type. For example, `primitive("string")` describes strings. Usually, you'd want to use one of the other combinators like `string`.

### `array`

```typescript
declare const array: <A>(type: Type<A>) => Type<A[]>;
```

```typescript
import { array } from "typecraft";
```

The `array` type combinator describes arrays. It takes a single type combinator, describing items of the array, as an input.

### `tuple`

```typescript
declare type Types<A> = {
  [T in keyof A]: Type<A[T]>;
};

declare const tuple: <A extends unknown[]>(...types: Types<A>) => Type<A>;
```

```typescript
import { tuple } from "typecraft";
```

The `tuple` type combinator describes tuples. It takes zero or more type combinators, describing items of the tuple, as an input.

### `record`

```typescript
declare const record: <A>(type: Type<A>) => Type<Record<PropertyKey, A>>;
```

```typescript
import { record } from "typecraft";
```

The `record` type combinator describes records. It takes a single type combinator, describing values of the record, as an input.

### `object`

```typescript
declare type Types<A> = {
  [T in keyof A]: Type<A[T]>;
};

declare const object: <A extends {}>(propTypes: Types<A>) => Type<A>;
```

```typescript
import { object } from "typecraft";
```

The `object` type combinator describes objects. It takes a single object whose values are type combinators as an input. Typecasting `object` returns a function which only succeeds if the input is an object with the shape of the object description provided.

### `nullable`

```typescript
declare const nullable: <A>(type: Type<A>) => Type<A | null>;
```

```typescript
import { nullable } from "typecraft";
```

The `nullable` type combinator describes nullable types. It takes a single type combinator as an input.

### `optional`

```typescript
declare const optional: <A>(type: Type<A>) => Type<A | undefined>;
```

```typescript
import { optional } from "typecraft";
```

The `optional` type combinator describes optional types. It takes a single type combinator as an input.

### `enumeration`

```typescript
declare type Primitive =
  | string
  | number
  | bigint
  | boolean
  | symbol
  | null
  | undefined;

declare const enumeration: <A extends Primitive[]>(
  ...values: A
) => Type<A[number]>;
```

```typescript
import type { Typedef } from "typecraft";
import { enumeration } from "typecraft";

// type Gender = "male" | "female";
type Gender = Typedef<typeof gender>;
const gender = enumeration("male", "female");
```

The `enumeration` type combinator describes an enum of primitive values. It takes zero or more primitive values as an input.

### `union`

```typescript
declare type Types<A> = {
  [T in keyof A]: Type<A[T]>;
};

declare const union: <A extends unknown[]>(
  ...types: Types<A>
) => Type<A[number]>;
```

```typescript
import type { Primitive, Type } from "typecraft";
import {
  string,
  number,
  bigint,
  boolean,
  symbol,
  primitive,
  union
} from "typecraft";

const simple: Type<Primitive> = union(
  string,
  number,
  bigint,
  boolean,
  symbol,
  primitive("null"),
  primitive("undefined")
);
```

The `union` type combinator describes a union of multiple types. It take one or more type combinators as an input.

### `intersection`

```typescript
declare type Types<A> = {
  [T in keyof A]: Type<A[T]>;
};

declare const intersection: <A extends unknown[]>(
  ...types: Types<A>
) => Type<A>;
```

```typescript
import type { Type } from "typecraft";
import { string, number, object, intersection } from "typecraft";

interface Foo {
  foo: string;
}

interface Bar {
  bar: string;
}

const foobar: Type<[Foo, Bar]> = intersection(
  object({ foo: string }),
  object({ bar: number })
);
```

The `intersection` type combinator describes an intersection of multiple types. It takes zero or more type combinators as an input. The type that it describes is similar to a tuple instead of a TypeScript intersection. However, it behaves like an intersection instead of a tuple.

### `pure`

```typescript
declare const pure: <A>(value: A) => Type<A>;
```

```typescript
import { pure } from "typecraft";
```

The `pure` type combinator describes a pure value. Typecasting `pure` always succeeds with the value provided and it ignores its input.

### `map`

```typescript
declare const map: <A, B>(morphism: (a: A) => B, type: Type<A>) => Type<B>;
```

```typescript
import { map } from "typecraft";
```

The `map` type combinator transforms the result of another type combinator.

### `fix`

```typescript
declare const fix: <A>(combinator: (type: Type<A>) => Type<A>) => Type<A>;
```

```typescript
import type { Type } from "typecraft";
import { number, object, nullable, fix } from "typecraft";

type List<A> = Cons<A> | null;

interface Cons<A> {
  head: A;
  tail: List<A>;
}

const list = <A>(head: Type<A>) =>
  fix<List<A>>((tail) => nullable(object({ head, tail })));
```

The `fix` type combinator describes recursive types. It takes a single type endomorphism as an input and ties the knot to create a cyclic type.

### `cast`

```typescript
declare type Cast<A> =
  | { status: "success"; value: A; values: A[] }
  | { status: "failure"; expected: "never"; actual: unknown }
  | { status: "failure"; expected: "string"; actual: unknown }
  | { status: "failure"; expected: "number"; actual: unknown }
  | { status: "failure"; expected: "bigint"; actual: unknown }
  | { status: "failure"; expected: "boolean"; actual: unknown }
  | { status: "failure"; expected: "symbol"; actual: unknown }
  | { status: "failure"; expected: "null"; actual: unknown }
  | { status: "failure"; expected: "undefined"; actual: unknown }
  | {
      status: "failure";
      expected: "array";
      items?: Cast<unknown>[];
      actual: unknown;
    }
  | {
      status: "failure";
      expected: "tuple";
      length: number;
      items?: Cast<unknown>[];
      actual: unknown;
    }
  | {
      status: "failure";
      expected: "record";
      properties?: Record<PropertyKey, Cast<unknown>>;
      actual: unknown;
    }
  | {
      status: "failure";
      expected: "record";
      properties?: Record<PropertyKey, Cast<unknown>>;
      actual: unknown;
    }
  | {
      status: "failure";
      expected: "enumeration";
      values: Set<Primitive>;
      actual: unknown;
    }
  | { status: "failure"; expected: "union"; variants: Cast<never>[] }
  | { status: "failure"; expected: "intersection"; results: Cast<unknown>[] };

declare const cast: <A>(type: Type<A>) => (input: unknown) => Cast<A>;
```

```typescript
import { cast } from "typecraft";
```

The `cast` function is used to create a typecasting function. It takes a `Type<A>` as an input and returns a functions which typecasts values to `A`.

---
_Source: https://npm.io/package/typecraft · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
