TypeScript specification and interface definitions for AI language model providers within the Vercel AI SDK ecosystem
—
Type-safe JSON handling utilities for working with structured data, providing runtime type checking and validation for JSON values.
Comprehensive type definitions for JSON data structures.
/**
* Union type representing all valid JSON values
*/
type JSONValue = null | string | number | boolean | JSONObject | JSONArray;
/**
* JSON object type with string keys and JSON values
*/
type JSONObject = { [key: string]: JSONValue };
/**
* JSON array type containing JSON values
*/
type JSONArray = JSONValue[];Runtime type checking functions to validate JSON data structures.
/**
* Check if a value is a valid JSON value
* @param value - Value to check
* @returns True if value is a valid JSON value
*/
function isJSONValue(value: unknown): value is JSONValue;
/**
* Check if a value is a JSON array
* @param value - Value to check
* @returns True if value is a JSON array
*/
function isJSONArray(value: unknown): value is JSONArray;
/**
* Check if a value is a JSON object
* @param value - Value to check
* @returns True if value is a JSON object (not null or array)
*/
function isJSONObject(value: unknown): value is JSONObject;Usage Examples:
import {
JSONValue,
JSONObject,
JSONArray,
isJSONValue,
isJSONArray,
isJSONObject
} from "@ai-sdk/provider";
// Basic type checking
function processUserData(data: unknown): JSONObject {
if (!isJSONObject(data)) {
throw new Error('Expected JSON object');
}
return data; // TypeScript now knows this is JSONObject
}
// Validate API response
async function fetchAndValidateData(url: string): Promise<JSONObject> {
const response = await fetch(url);
const data = await response.json();
if (!isJSONValue(data)) {
throw new Error('Response is not valid JSON');
}
if (!isJSONObject(data)) {
throw new Error('Expected JSON object response');
}
return data;
}
// Safe array processing
function processItems(items: unknown): string[] {
if (!isJSONArray(items)) {
throw new Error('Expected JSON array');
}
return items
.filter((item): item is string => typeof item === 'string')
.map(item => item.trim());
}
// Deep JSON validation
function validateJSONStructure(data: unknown): JSONValue {
if (data === null) return null;
if (typeof data === 'string' ||
typeof data === 'number' ||
typeof data === 'boolean') {
return data;
}
if (Array.isArray(data)) {
return data.map(validateJSONStructure) as JSONArray;
}
if (typeof data === 'object') {
const result: JSONObject = {};
for (const [key, value] of Object.entries(data)) {
result[key] = validateJSONStructure(value);
}
return result;
}
throw new Error(`Invalid JSON value: ${typeof data}`);
}
// Schema validation helper
interface UserSchema {
name: string;
age: number;
email: string;
preferences: {
theme: 'light' | 'dark';
notifications: boolean;
};
tags: string[];
}
function validateUserSchema(data: unknown): UserSchema {
if (!isJSONObject(data)) {
throw new Error('Expected user object');
}
// Validate required fields
if (typeof data.name !== 'string') {
throw new Error('Name must be a string');
}
if (typeof data.age !== 'number') {
throw new Error('Age must be a number');
}
if (typeof data.email !== 'string') {
throw new Error('Email must be a string');
}
// Validate nested object
if (!isJSONObject(data.preferences)) {
throw new Error('Preferences must be an object');
}
const prefs = data.preferences;
if (prefs.theme !== 'light' && prefs.theme !== 'dark') {
throw new Error('Theme must be light or dark');
}
if (typeof prefs.notifications !== 'boolean') {
throw new Error('Notifications must be boolean');
}
// Validate array
if (!isJSONArray(data.tags)) {
throw new Error('Tags must be an array');
}
if (!data.tags.every((tag): tag is string => typeof tag === 'string')) {
throw new Error('All tags must be strings');
}
return data as UserSchema;
}
// Safe JSON parsing with validation
function safeParseJSON(text: string): JSONValue {
try {
const parsed = JSON.parse(text);
if (!isJSONValue(parsed)) {
throw new Error('Parsed value is not valid JSON');
}
return parsed;
} catch (error) {
throw new Error(`JSON parse error: ${error.message}`);
}
}
// JSON transformation utilities
function transformJSONObject(
obj: JSONObject,
transformer: (key: string, value: JSONValue) => JSONValue
): JSONObject {
const result: JSONObject = {};
for (const [key, value] of Object.entries(obj)) {
result[key] = transformer(key, value);
}
return result;
}
function flattenJSONObject(obj: JSONObject, prefix = ''): Record<string, JSONValue> {
const result: Record<string, JSONValue> = {};
for (const [key, value] of Object.entries(obj)) {
const newKey = prefix ? `${prefix}.${key}` : key;
if (isJSONObject(value)) {
Object.assign(result, flattenJSONObject(value, newKey));
} else {
result[newKey] = value;
}
}
return result;
}
// Type-safe access patterns
class JSONNavigator {
constructor(private data: JSONValue) {}
get(path: string): JSONValue | undefined {
const keys = path.split('.');
let current = this.data;
for (const key of keys) {
if (!isJSONObject(current)) {
return undefined;
}
current = current[key];
if (current === undefined) {
return undefined;
}
}
return current;
}
getString(path: string): string | undefined {
const value = this.get(path);
return typeof value === 'string' ? value : undefined;
}
getNumber(path: string): number | undefined {
const value = this.get(path);
return typeof value === 'number' ? value : undefined;
}
getBoolean(path: string): boolean | undefined {
const value = this.get(path);
return typeof value === 'boolean' ? value : undefined;
}
getArray(path: string): JSONArray | undefined {
const value = this.get(path);
return isJSONArray(value) ? value : undefined;
}
getObject(path: string): JSONObject | undefined {
const value = this.get(path);
return isJSONObject(value) ? value : undefined;
}
}
// Usage examples
const userData: unknown = {
name: "Alice",
age: 30,
preferences: {
theme: "dark",
notifications: true
},
tags: ["developer", "typescript"]
};
if (isJSONObject(userData)) {
const navigator = new JSONNavigator(userData);
console.log('Name:', navigator.getString('name'));
console.log('Age:', navigator.getNumber('age'));
console.log('Theme:', navigator.getString('preferences.theme'));
console.log('Tags:', navigator.getArray('tags'));
}
// Batch validation
function validateBatch(items: unknown[]): JSONValue[] {
return items.map((item, index) => {
if (!isJSONValue(item)) {
throw new Error(`Item at index ${index} is not valid JSON`);
}
return item;
});
}
// JSON diff utility
function compareJSON(a: JSONValue, b: JSONValue): boolean {
if (a === b) return true;
if (isJSONArray(a) && isJSONArray(b)) {
if (a.length !== b.length) return false;
return a.every((item, index) => compareJSON(item, b[index]));
}
if (isJSONObject(a) && isJSONObject(b)) {
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length !== keysB.length) return false;
return keysA.every(key =>
keysB.includes(key) && compareJSON(a[key], b[key])
);
}
return false;
}
// Usage in AI SDK context
function processModelResponse(response: unknown): JSONObject {
// Validate the response is JSON
if (!isJSONValue(response)) {
throw new InvalidResponseDataError({ data: response });
}
// Ensure it's an object
if (!isJSONObject(response)) {
throw new InvalidResponseDataError({ data: response });
}
return response;
}
function extractToolArgs(toolCall: unknown): JSONObject {
if (!isJSONObject(toolCall)) {
throw new Error('Tool call must be an object');
}
const args = toolCall.args;
if (!isJSONObject(args)) {
throw new Error('Tool arguments must be an object');
}
return args;
}Install with Tessl CLI
npx tessl i tessl/npm-ai-sdk--provider