A collection of codecs and combinators for use with io-ts
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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.
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;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]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 }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 }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
}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}`);
}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}'
}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 structureimport * 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}`);
}
}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 objectimport * 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