Comprehensive type definitions for JSON data structures, providing type-safe alternatives to any for JSON operations. This is one of the key improvements in better-typescript-lib.
The global JSON object with improved type safety for parsing and stringifying operations.
interface JSON {
/**
* Converts a JSON string into an object.
* Returns JSONValue instead of any for better type safety.
*/
parse(text: string): JSONValue;
/**
* Converts a JSON string into an object with a reviver function.
* Generic version allowing custom return types.
*/
parse<A = unknown>(
text: string,
reviver: <K extends string>(
this: JSONHolder<K, A>,
key: K,
value: JSONValueF<A>,
) => A,
): A;
/**
* Converts a JavaScript value to a JSON string.
*/
stringify<A>(
value: A,
replacer?: (string | number)[] | null | undefined,
space?: string | number | null | undefined,
): StringifyResult<ToJSON<A>>;
/**
* Converts a JavaScript value to a JSON string with replacer function.
*/
stringify<A>(
value: A,
replacer:
| ((
this: JSONComposite<A>,
key: string,
value: ToJSON<A>,
) => JSONValueF<A>)
| null
| undefined,
space?: string | number | null | undefined,
): string;
}Usage Examples:
// Basic JSON parsing - now returns JSONValue instead of any
const data = JSON.parse('{"name": "Alice", "age": 30, "active": true}');
// data is JSONValue, requiring type guards for safe access
// Type-safe property access
if (typeof data === 'object' && data !== null && !Array.isArray(data)) {
const name = data.name; // Type: JSONValue | undefined
if (typeof name === 'string') {
console.log(name.toUpperCase()); // Safe string operation
}
}
// Using reviver function with custom types
type UserData = {
name: string;
birthDate: Date;
};
const userData = JSON.parse<UserData>('{"name": "Bob", "birthDate": "2023-01-01"}',
(key, value) => {
if (key === 'birthDate' && typeof value === 'string') {
return new Date(value);
}
return value;
}
);Fundamental type definitions for representing JSON data structures.
/**
* Primitive values that can be represented in JSON
*/
type JSONPrimitive = string | number | boolean | null;
/**
* Any value that can be represented in JSON
*/
type JSONValue = JSONPrimitive | JSONObject | JSONValue[];
/**
* A JSON object (key-value pairs)
*/
type JSONObject = { [key: string]: JSONValue };
/**
* Generic JSON composite type allowing additional value types
*/
type JSONComposite<A> = { [key: string]: JSONValueF<A> } | JSONValueF<A>[];
/**
* Generic JSON value type with parameterized additional types
*/
type JSONValueF<A> = JSONPrimitive | JSONComposite<A>;
/**
* Record type for JSON data with specific key and value constraints
*/
type JSONHolder<K extends string, A> = Record<K, JSONValueF<A>>;
/**
* Utility type for JSON stringification
*/
type ToJSON<A> = A extends { toJSON(...args: any): infer T } ? T : A;
/**
* Helper types for stringify result handling
*/
type SomeFunction = (...args: any) => any;
type SomeConstructor = new (...args: any) => any;
type UndefinedDomain = symbol | SomeFunction | SomeConstructor | undefined;
type SomeExtends<A, B> = A extends B ? undefined : never;
type StringifyResultT<A> = A extends UndefinedDomain ? undefined : string;
type StringifyResult<A> = StringifyResultT<A> | SomeExtends<UndefinedDomain, A>;Usage Examples:
// Working with JSONValue
function processUserData(data: JSONValue): void {
if (typeof data === 'object' && data !== null && !Array.isArray(data)) {
// data is JSONObject
const name = data.name;
if (typeof name === 'string') {
console.log(`Processing user: ${name}`);
}
}
}
// Creating type-safe JSON structures
const userProfile: JSONObject = {
id: 123,
name: "Alice",
email: "alice@example.com",
preferences: {
theme: "dark",
notifications: true
},
tags: ["developer", "typescript"]
};
// Working with JSONValueF for extended types
type JSONWithDate = JSONValueF<Date>;
function handleExtendedJSON(data: JSONWithDate): void {
if (data instanceof Date) {
console.log(`Date: ${data.toISOString()}`);
} else if (typeof data === 'object' && data !== null) {
// Handle JSON object or array
}
}Utility functions for safely working with JSON types.
// Example type guards you can implement
function isJSONObject(value: JSONValue): value is JSONObject {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function isJSONArray(value: JSONValue): value is JSONValue[] {
return Array.isArray(value);
}
function isJSONPrimitive(value: JSONValue): value is JSONPrimitive {
return value === null ||
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'boolean';
}
// Usage with type guards
const jsonData = JSON.parse(jsonString);
if (isJSONObject(jsonData)) {
// jsonData is now typed as JSONObject
const keys = Object.keys(jsonData);
for (const key of keys) {
const value = jsonData[key];
// value is JSONValue
}
}Working with complex JSON structures and generic types.
// Custom JSON value types for specific domains
type APIResponse = JSONValueF<{
timestamp: Date;
version: string;
}>;
// Working with nested JSON structures
interface UserJSON extends JSONObject {
id: number;
profile: {
name: string;
email: string;
settings: JSONObject;
};
history: JSONValue[];
}
// Type-safe JSON transformation
function transformJSONUser(data: JSONValue): UserJSON | null {
if (!isJSONObject(data)) return null;
const id = data.id;
const profile = data.profile;
if (typeof id !== 'number' || !isJSONObject(profile)) {
return null;
}
return data as UserJSON;
}