Data that comes back from a network request is any — TypeScript trusts your cast, but the server might send something else. $mol ships two small runtime-schema libraries that turn untrusted JSON into a typed, validated value and fail loudly, with a readable path, when the shape is wrong. Use them right where data enters the app, most often on a fetch response.
$mol_data — concise, functional parsers (zod-like). You compose small parser functions and call the result on a value.$mol_schema — class-based schemas with defaults. You extend a record class and get .guard(), .cast(), .check(), and a .default.Both validate at runtime and infer the static type for you. Reach for $mol_data for quick DTOs and (de)serialization; reach for $mol_schema when you want named, reusable schema classes with default values and relaxed casting.
Describe the shape as a record of field parsers:1const UserDTO=$mol_data_record({2name:$mol_data_string,3age:$mol_data_optional($mol_data_integer),4mail:$mol_data_email,5})Call it on the raw value. Valid data passes through, fully typed; bad data throws a $mol_data_error naming the exact path that failed:1const user=UserDTO(json)2// user: { readonly name: string; readonly age?: number; readonly mail: string }34// If json.mail is "</script>", it throws:5// ["mail"] </script> is not a /.+@.+/Reuse the inferred type anywhere with typeof UserDTO.Value:1function greet(user:typeofUserDTO.Value){2return `Hello, ${ user.name }`3}The building blocks include $mol_data_string, $mol_data_number, $mol_data_integer, $mol_data_boolean, $mol_data_email, $mol_data_optional, $mol_data_nullable, $mol_data_variant (one of several types), $mol_data_array, $mol_data_dict, and $mol_data_record. $mol_data_pipe feeds a parsed value into a transform, for example an ISO string into a $mol_time_moment, which doubles as (de)serialization.
Define a schema as a class that extends a record:1export class $my_userextends$mol_schema_record({2name:$mol_schema_string,3age:$mol_schema_natural,4}){}You then have three ways to apply it, plus a ready-made default:1const safe=$my_user.guard(input)// strict: throws on wrong data2const relaxed=$my_user.cast(input)// fills defaults instead of throwing3if ($my_user.check(input)){/* input is $my_user in here */}4const blank=$my_user.default// { name: '', age: 0 }Leaf schemas include $mol_schema_string, $mol_schema_integer, $mol_schema_natural, $mol_schema_float, $mol_schema_boolean, $mol_schema_enum([...]), and $mol_schema_pattern(/re/). Compose them with $mol_schema_list(Item), $mol_schema_dict([Key,Val]), $mol_schema_maybe(S) (value, null, or undefined), $mol_schema_some([...]) (a union), and $mol_schema_partial({...}). Spread another record's fields with ...Base.Fields:Edit this page on GitHubWas this helpful?YesNoPreviousData FetchingNextGiper BazaOn this pageTwo libraries$mol_data$mol_schemaValidating a fetch responseNextType to search the documentation.