npm package: @schemashift/io-ts-effect
Description: io-ts → Effect Schema transformer for SchemaShift
Author: Joseph May
Latest version: 0.14.0

# @schemashift/io-ts-effect

io-ts → Effect Schema transformer for SchemaShift. Migrates io-ts codecs to their Effect Schema equivalents — the official successor to io-ts after fp-ts merged into Effect.

[![npm version](https://img.shields.io/npm/v/@schemashift/io-ts-effect.svg)](https://www.npmjs.com/package/@schemashift/io-ts-effect)
[![npm downloads](https://img.shields.io/npm/dm/@schemashift/io-ts-effect.svg)](https://www.npmjs.com/package/@schemashift/io-ts-effect)
[![CI](https://github.com/jdmay2/schemashift/actions/workflows/ci.yml/badge.svg)](https://github.com/jdmay2/schemashift/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

**Tier:** Pro+

## Installation

```bash
npm install @schemashift/io-ts-effect
```

## Usage

```typescript
import { createIoTsToEffectHandler } from '@schemashift/io-ts-effect';
import { TransformEngine } from '@schemashift/core';

const engine = new TransformEngine();
engine.registerHandler('io-ts', 'effect', createIoTsToEffectHandler());
```

## Why This Migration Path?

- **io-ts is deprecated** — fp-ts merged into Effect-TS
- **Effect Schema is the official successor** for FP-oriented validation
- **Same philosophy** — both use branded types, codecs, and composable validation
- **Better DX** — Effect Schema has simpler API with better TypeScript inference

## Transformation Mappings

### Imports

| io-ts | Effect Schema |
|-------|---------------|
| `import * as t from 'io-ts'` | `import { Schema as S } from '@effect/schema'` |
| `import { pipe } from 'fp-ts/function'` | `import { pipe } from 'effect/Function'` |

### Primitives

| io-ts | Effect Schema |
|-------|---------------|
| `t.string` | `S.String` |
| `t.number` | `S.Number` |
| `t.boolean` | `S.Boolean` |
| `t.bigint` | `S.BigInt` |
| `t.unknown` | `S.Unknown` |
| `t.never` | `S.Never` |
| `t.null` | `S.Null` |
| `t.undefined` | `S.Undefined` |
| `t.void` | `S.Void` |

### Combinators

| io-ts | Effect Schema |
|-------|---------------|
| `t.type({...})` | `S.Struct({...})` |
| `t.partial({...})` | `S.partial(S.Struct({...}))` |
| `t.array(X)` | `S.Array(X)` |
| `t.record(K, V)` | `S.Record(K, V)` |
| `t.union([A, B])` | `S.Union(A, B)` |
| `t.tuple([A, B])` | `S.Tuple(A, B)` |
| `t.literal(X)` | `S.Literal(X)` |

### Type Helpers

| io-ts | Effect Schema |
|-------|---------------|
| `t.TypeOf<typeof s>` | `S.Schema.Type<typeof s>` |
| `t.OutputOf<typeof s>` | `S.Schema.Type<typeof s>` |
| `t.InputOf<typeof s>` | `S.Schema.Encoded<typeof s>` |

## Patterns Requiring Manual Review

### `.decode()` / `.encode()`

```typescript
// io-ts
const result = schema.decode(input);

// Effect Schema
const result = S.decodeUnknownSync(schema)(input);
// or for Either result:
const result = S.decodeUnknownEither(schema)(input);
```

### `t.brand()`

```typescript
// io-ts
interface PositiveBrand { readonly Positive: unique symbol }
const Positive = t.brand(t.number, (n): n is t.Branded<number, PositiveBrand> => n > 0, 'Positive');

// Effect Schema
const Positive = pipe(S.Number, S.positive(), S.brand("Positive"));
```

### Recursive Types

```typescript
// io-ts
const Tree = t.recursion('Tree', () => t.type({ children: t.array(Tree) }));

// Effect Schema
const Tree = S.Struct({ children: S.Array(S.suspend(() => Tree)) });
```

## Related Packages

- [schemashift-cli](https://www.npmjs.com/package/schemashift-cli) — CLI tool for running migrations
- [@schemashift/core](https://www.npmjs.com/package/@schemashift/core) — Core analysis engine
- [@schemashift/io-ts-zod](https://www.npmjs.com/package/@schemashift/io-ts-zod) — Alternative: io-ts → Zod

## License

MIT