CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-io-ts-types

A collection of codecs and combinators for use with io-ts

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

json-handling.mddocs/

JSON Handling

Comprehensive JSON parsing and validation with proper type definitions for all JSON value types. These codecs provide safe parsing and serialization of JSON data with full type safety.

Capabilities

JSON Type Definitions

Complete type definitions for all possible JSON values, enabling type-safe JSON manipulation.

/**
 * Interface for JSON objects with string keys
 */
interface JsonRecord {
  readonly [key: string]: Json;
}

/**
 * Interface for JSON arrays extending ReadonlyArray
 */
interface JsonArray extends ReadonlyArray<Json> {}

/**
 * Union type representing any valid JSON value
 * Includes all primitive JSON types and recursive structures
 */
type Json = boolean | number | string | null | JsonArray | JsonRecord;

JSON Array Codec

Codec for validating and working with JSON arrays specifically.

/**
 * Codec for JSON arrays
 * Validates arrays where all elements are valid JSON values
 */
const JsonArray: t.Type<JsonArray>;

Usage Examples:

import { JsonArray } from "io-ts-types";

const result1 = JsonArray.decode([1, "hello", true, null]);
// Right([1, "hello", true, null] as JsonArray)

const result2 = JsonArray.decode([1, [2, 3], { key: "value" }]);
// Right([1, [2, 3], { key: "value" }] as JsonArray)

const result3 = JsonArray.decode([]);
// Right([] as JsonArray) - empty array is valid

const result4 = JsonArray.decode([1, undefined, 3]);
// Left([ValidationError]) - undefined is not a valid JSON value

const result5 = JsonArray.decode("not-an-array");
// Left([ValidationError]) - not an array

// Encoding is identity for valid JSON arrays
const encoded = JsonArray.encode([1, "test", null]);
// [1, "test", null]

JSON Record Codec

Codec for validating and working with JSON objects specifically.

/**
 * Codec for JSON objects (records)
 * Validates objects where all values are valid JSON values
 */
const JsonRecord: t.Type<JsonRecord>;

Usage Examples:

import { JsonRecord } from "io-ts-types";

const result1 = JsonRecord.decode({ 
  name: "Alice", 
  age: 25, 
  active: true, 
  metadata: null 
});
// Right({ name: "Alice", age: 25, active: true, metadata: null } as JsonRecord)

const result2 = JsonRecord.decode({
  users: [{ id: 1, name: "Bob" }],
  config: { enabled: true, timeout: 30 }
});
// Right({ users: [...], config: {...} } as JsonRecord)

const result3 = JsonRecord.decode({});
// Right({} as JsonRecord) - empty object is valid

const result4 = JsonRecord.decode({ 
  valid: "value", 
  invalid: undefined 
});
// Left([ValidationError]) - undefined is not a valid JSON value

const result5 = JsonRecord.decode([1, 2, 3]);
// Left([ValidationError]) - array is not a record

// Encoding is identity for valid JSON records
const encoded = JsonRecord.encode({ key: "value", number: 42 });
// { key: "value", number: 42 }

JSON Value Codec

Codec for any valid JSON value, providing comprehensive JSON validation.

/**
 * Codec for any valid JSON value
 * Validates any value that can be represented in JSON
 */
const Json: t.Type<Json>;

Usage Examples:

import { Json } from "io-ts-types";

// Primitive JSON values
const result1 = Json.decode(42);
// Right(42 as Json)

const result2 = Json.decode("hello");
// Right("hello" as Json)

const result3 = Json.decode(true);
// Right(true as Json)

const result4 = Json.decode(null);
// Right(null as Json)

// Complex JSON structures
const result5 = Json.decode({
  name: "Alice",
  scores: [95, 87, 92],
  metadata: {
    created: "2023-12-25",
    tags: ["student", "honor-roll"]
  }
});
// Right({...} as Json)

// Invalid JSON values
const result6 = Json.decode(undefined);
// Left([ValidationError]) - undefined not valid in JSON

const result7 = Json.decode(Symbol("test"));
// Left([ValidationError]) - symbols not valid in JSON

const result8 = Json.decode(() => {});
// Left([ValidationError]) - functions not valid in JSON

// Encoding is identity for valid JSON
const encoded = Json.encode({ key: [1, 2, 3], flag: true });
// { key: [1, 2, 3], flag: true }

JSON String Parsing

Codec that parses JSON strings to Json values and stringifies Json values back to strings.

/**
 * Codec that parses JSON strings to Json values
 * Handles JSON.parse() and JSON.stringify() operations safely
 */
const JsonFromString: t.Type<Json, string, string>;

Usage Examples:

import { JsonFromString } from "io-ts-types";

// Valid JSON strings
const result1 = JsonFromString.decode('{"name": "Alice", "age": 25}');
// Right({ name: "Alice", age: 25 } as Json)

const result2 = JsonFromString.decode('[1, 2, 3, "hello"]');
// Right([1, 2, 3, "hello"] as Json)

const result3 = JsonFromString.decode('"simple string"');
// Right("simple string" as Json)

const result4 = JsonFromString.decode('42');
// Right(42 as Json)

const result5 = JsonFromString.decode('true');
// Right(true as Json)

const result6 = JsonFromString.decode('null');
// Right(null as Json)

// Invalid JSON strings
const result7 = JsonFromString.decode('{"invalid": json}');
// Left([ValidationError]) - invalid JSON syntax

const result8 = JsonFromString.decode('undefined');
// Left([ValidationError]) - undefined is not valid JSON

const result9 = JsonFromString.decode('');
// Left([ValidationError]) - empty string is not valid JSON

// Encoding Json back to string
const jsonValue = { name: "Bob", items: [1, 2, 3] };
const encoded = JsonFromString.encode(jsonValue);
// '{"name":"Bob","items":[1,2,3]}' - stringified JSON

// Round-trip example
const originalString = '{"test": true, "count": 42}';
const parsed = JsonFromString.decode(originalString);
if (parsed._tag === "Right") {
  const backToString = JsonFromString.encode(parsed.right);
  // backToString might be formatted differently but semantically equivalent
}

Common Usage Patterns

API Response Processing

import * as t from "io-ts";
import { JsonFromString, Json } from "io-ts-types";

const ApiResponse = t.type({
  status: t.string,
  data: Json,           // Any JSON data
  metadata: Json        // Any JSON metadata
});

// Process API response with mixed JSON data
const responseData = {
  status: "success",
  data: {
    users: [
      { id: 1, name: "Alice", active: true },
      { id: 2, name: "Bob", active: false }
    ],
    pagination: { page: 1, total: 100 }
  },
  metadata: {
    timestamp: "2023-12-25T10:30:00Z",
    version: "1.0",
    cached: false
  }
};

const parsed = ApiResponse.decode(responseData);
// Right({ status: "success", data: Json, metadata: Json })

// Safe access to JSON data
if (parsed._tag === "Right") {
  const { data, metadata } = parsed.right;
  
  // data and metadata are typed as Json, enabling safe manipulation
  console.log(`API version: ${(metadata as any).version}`);
  console.log(`User count: ${((data as any).users as any[]).length}`);
}

Configuration File Processing

import * as t from "io-ts";
import { JsonFromString } from "io-ts-types";

const ConfigFile = t.type({
  name: t.string,
  settings: JsonFromString,  // JSON string that gets parsed
  overrides: JsonFromString
});

// Configuration with JSON strings
const configData = {
  name: "MyApp",
  settings: '{"theme": "dark", "notifications": true, "timeout": 30000}',
  overrides: '{"debug": true, "logLevel": "verbose"}'
};

const validated = ConfigFile.decode(configData);

if (validated._tag === "Right") {
  const config = validated.right;
  
  // settings and overrides are now parsed JSON objects
  console.log(`Theme: ${(config.settings as any).theme}`);
  console.log(`Debug mode: ${(config.overrides as any).debug}`);
  
  // Can encode back to JSON strings
  const settingsString = JsonFromString.encode(config.settings);
  // '{"theme":"dark","notifications":true,"timeout":30000}'
}

Dynamic Content Handling

import * as t from "io-ts";
import { Json, JsonRecord, JsonArray } from "io-ts-types";

const ContentBlock = t.type({
  type: t.string,
  id: t.string,
  data: Json,              // Flexible JSON data
  attributes: JsonRecord,   // Must be a JSON object
  children: JsonArray       // Must be a JSON array
});

const contentData = {
  type: "article",
  id: "post_123",
  data: {
    title: "Getting Started",
    body: "Welcome to our platform...",
    published: true,
    tags: ["tutorial", "beginner"]
  },
  attributes: {
    author: "Alice",
    category: "documentation",
    featured: false
  },
  children: [
    { type: "paragraph", content: "First paragraph..." },
    { type: "image", src: "example.jpg", alt: "Example" }
  ]
};

const validated = ContentBlock.decode(contentData);
// All JSON fields are validated for proper JSON structure

Form Data with JSON Fields

import * as t from "io-ts";
import { JsonFromString, Json } from "io-ts-types";

const FormSubmission = t.type({
  userId: t.string,
  formType: t.string,
  formData: JsonFromString,    // JSON string from form
  metadata: t.union([JsonFromString, t.null])
});

// Form submission with JSON fields
const submission = {
  userId: "user_123",
  formType: "contact",
  formData: '{"name": "Alice", "email": "alice@example.com", "message": "Hello!"}',
  metadata: '{"source": "website", "referrer": "google.com"}'
};

const validated = FormSubmission.decode(submission);

if (validated._tag === "Right") {
  const form = validated.right;
  
  // formData is now a parsed JSON object
  const parsedData = form.formData as any;
  console.log(`Contact from: ${parsedData.name} <${parsedData.email}>`);
  console.log(`Message: ${parsedData.message}`);
  
  // metadata is also parsed (or null)
  if (form.metadata !== null) {
    const meta = form.metadata as any;
    console.log(`Source: ${meta.source}, Referrer: ${meta.referrer}`);
  }
}

Database Record with JSON Columns

import * as t from "io-ts";
import { Json, JsonRecord } from "io-ts-types";

const DatabaseRecord = t.type({
  id: t.number,
  name: t.string,
  data: Json,              // JSON column - any valid JSON
  settings: JsonRecord,    // JSON column - must be object
  created_at: t.string
});

// Database record with JSON columns
const record = {
  id: 1,
  name: "User Profile",
  data: {
    profile: {
      avatar: "avatar.jpg",
      bio: "Software developer",
      social: {
        twitter: "@alice_dev",
        github: "alice-codes"
      }
    },
    preferences: {
      theme: "dark",
      notifications: ["email", "push"],
      privacy: { public: false }
    }
  },
  settings: {
    language: "en",
    timezone: "UTC",
    currency: "USD"
  },
  created_at: "2023-12-25T10:30:00Z"
};

const validated = DatabaseRecord.decode(record);
// Ensures data is valid JSON and settings is a valid JSON object

API Webhook Payload

import * as t from "io-ts";
import { Json, JsonFromString } from "io-ts-types";

const WebhookPayload = t.type({
  event: t.string,
  timestamp: t.string,
  payload: Json,           // Event data - any JSON structure
  signature: t.string,
  raw: JsonFromString      // Raw payload string for signature verification
});

const webhookData = {
  event: "user.created",
  timestamp: "2023-12-25T10:30:00Z",
  payload: {
    user: {
      id: 123,
      email: "new-user@example.com",
      created_at: "2023-12-25T10:30:00Z"
    },
    metadata: {
      source: "registration_form",
      ip_address: "192.168.1.1"
    }
  },
  signature: "sha256=abc123...",
  raw: '{"user":{"id":123,"email":"new-user@example.com","created_at":"2023-12-25T10:30:00Z"},"metadata":{"source":"registration_form","ip_address":"192.168.1.1"}}'
};

const validated = WebhookPayload.decode(webhookData);
// Validates event payload structure and parses raw JSON string

docs

branded-types-validation.md

collection-codecs.md

date-handling.md

functional-programming-types.md

index.md

json-handling.md

string-number-transformations.md

utility-functions-codec-modifiers.md

tile.json