[{"data":1,"prerenderedAt":2364},["ShallowReactive",2],{"navigation_docs":3,"-guide-serialization":127,"-guide-serialization-surround":2359},[4,19,53,71,95],{"title":5,"icon":6,"redirect":7,"path":8,"stem":9,"children":10,"page":18},"Introduction","i-lucide-rocket","\u002Fintroduction\u002Fabout-ts-runtypes","\u002Fintroduction","1.introduction",[11,14],{"title":12,"path":7,"stem":13},"About RunTypes","1.introduction\u002F1.about-ts-runtypes",{"title":15,"path":16,"stem":17},"Quick Start","\u002Fintroduction\u002Fquick-start","1.introduction\u002F2.quick-start",false,{"title":20,"icon":21,"redirect":22,"path":23,"stem":24,"children":25,"page":18},"Guide","i-lucide-book-open","\u002Fguide\u002Ftypes-vs-schemas","\u002Fguide","2.guide",[26,29,33,37,41,45,49],{"title":27,"path":22,"stem":28},"Types vs Schemas","2.guide\u002F1.types-vs-schemas",{"title":30,"path":31,"stem":32},"Type Formats","\u002Fguide\u002Ftype-formats","2.guide\u002F2.type-formats",{"title":34,"path":35,"stem":36},"Serialization","\u002Fguide\u002Fserialization","2.guide\u002F3.serialization",{"title":38,"path":39,"stem":40},"Mock Data","\u002Fguide\u002Fmocking","2.guide\u002F4.mocking",{"title":42,"path":43,"stem":44},"Validation","\u002Fguide\u002Fvalidation","2.guide\u002F5.validation",{"title":46,"path":47,"stem":48},"Reflection","\u002Fguide\u002Fmarkers-and-reflection","2.guide\u002F6.markers-and-reflection",{"title":50,"path":51,"stem":52},"Pure Functions","\u002Fguide\u002Fpure-functions","2.guide\u002F7.pure-functions",{"title":54,"icon":55,"redirect":56,"path":57,"stem":58,"children":59,"page":18},"AI Integration","i-lucide-sparkles","\u002Fai-integration\u002Fworkflow-and-commands","\u002Fai-integration","3.ai-integration",[60,63,67],{"title":61,"path":56,"stem":62},"AI Workflow","3.ai-integration\u002F1.workflow-and-commands",{"title":64,"path":65,"stem":66},"FriendlyType","\u002Fai-integration\u002Ffriendly-type","3.ai-integration\u002F2.friendly-type",{"title":68,"path":69,"stem":70},"MockData","\u002Fai-integration\u002Fmock-data","3.ai-integration\u002F3.mock-data",{"title":72,"icon":73,"redirect":74,"path":75,"stem":76,"children":77,"page":18},"Test Suites","i-lucide-terminal","\u002Fsuites\u002Fvalidation","\u002Fsuites","6.suites",[78,80,83,87,91],{"title":42,"path":74,"stem":79},"6.suites\u002F1.validation",{"title":34,"path":81,"stem":82},"\u002Fsuites\u002Fserialization","6.suites\u002F2.serialization",{"title":84,"path":85,"stem":86},"Formats Validation","\u002Fsuites\u002Fformat-validation","6.suites\u002F3.format-validation",{"title":88,"path":89,"stem":90},"Formats Serialization","\u002Fsuites\u002Fformat-serialization","6.suites\u002F4.format-serialization",{"title":92,"path":93,"stem":94},"Fuzzing","\u002Fsuites\u002Ffuzzing","6.suites\u002F5.fuzzing",{"title":96,"icon":97,"redirect":98,"path":99,"stem":100,"children":101,"page":18},"Benchmarks","i-lucide-gauge","\u002Fbenchmarks\u002Fvalidation","\u002Fbenchmarks","7.benchmarks",[102,104,108,112,116,119,123],{"title":42,"path":98,"stem":103},"7.benchmarks\u002F1.validation",{"title":105,"path":106,"stem":107},"Validation Formats","\u002Fbenchmarks\u002Fvalidation-formats","7.benchmarks\u002F2.validation-formats",{"title":109,"path":110,"stem":111},"Validation Errors","\u002Fbenchmarks\u002Fgetvalidationerrors","7.benchmarks\u002F3.getvalidationerrors",{"title":113,"path":114,"stem":115},"Validation Error Formats","\u002Fbenchmarks\u002Fgetvalidationerrors-formats","7.benchmarks\u002F4.getvalidationerrors-formats",{"title":34,"path":117,"stem":118},"\u002Fbenchmarks\u002Fserialization","7.benchmarks\u002F5.serialization",{"title":120,"path":121,"stem":122},"Serialization Formats","\u002Fbenchmarks\u002Fserialization-formats","7.benchmarks\u002F6.serialization-formats",{"title":124,"path":125,"stem":126},"Compile Time","\u002Fbenchmarks\u002Fcompiletime","7.benchmarks\u002F7.compiletime",{"id":128,"title":34,"body":129,"description":2353,"extension":2354,"links":2355,"meta":2356,"navigation":254,"path":35,"seo":2357,"stem":36,"__hash__":2358},"docs\u002F2.guide\u002F3.serialization.md",{"type":130,"value":131},"minimark",[132,137,180,347,353,385,390,399,563,566,654,663,667,683,794,801,805,820,1054,1063,1067,1093,1609,1617,1628,1632,1659,1799,1811,1937,1944,2117,2143,2150,2167,2269,2272,2276,2289,2308,2312,2349],[133,134,136],"h2",{"id":135},"json-encode-decode","JSON encode \u002F decode",[138,139,140,144,145,148,149,152,153,156,157,160,161,156,164,167,168,170,171,170,174,160,176,179],"p",{},[141,142,143],"code",{},"createJsonEncoder"," \u002F ",[141,146,147],{},"createJsonDecoder"," understand the types ",[141,150,151],{},"JSON.stringify"," can't. Because the codec is generated from your type, it knows ",[141,154,155],{},"startedAt"," is a ",[141,158,159],{},"Date"," and ",[141,162,163],{},"flags",[141,165,166],{},"Map",". So ",[141,169,159],{},", ",[141,172,173],{},"BigInt",[141,175,166],{},[141,177,178],{},"Set"," all survive the round-trip.",[181,182,187],"pre",{"className":183,"code":184,"language":185,"meta":186,"style":186},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const encode = createJsonEncoder\u003CSession>();\nconst decode = createJsonDecoder\u003CSession>();\n\nconst wire = encode(session); \u002F\u002F a JSON string — Date and Map survive\nconst back = decode(wire); \u002F\u002F Date is a Date again, Map is a Map again\n\nback.startedAt instanceof Date; \u002F\u002F true\nback.flags instanceof Map; \u002F\u002F true\n","ts","",[141,188,189,226,249,256,279,300,305,328],{"__ignoreMap":186},[190,191,194,198,202,206,210,213,217,220,223],"span",{"class":192,"line":193},"line",1,[190,195,197],{"class":196},"spNyl","const",[190,199,201],{"class":200},"sTEyZ"," encode ",[190,203,205],{"class":204},"sMK4o","=",[190,207,209],{"class":208},"s2Zo4"," createJsonEncoder",[190,211,212],{"class":204},"\u003C",[190,214,216],{"class":215},"sBMFI","Session",[190,218,219],{"class":204},">",[190,221,222],{"class":200},"()",[190,224,225],{"class":204},";\n",[190,227,229,231,234,236,239,241,243,245,247],{"class":192,"line":228},2,[190,230,197],{"class":196},[190,232,233],{"class":200}," decode ",[190,235,205],{"class":204},[190,237,238],{"class":208}," createJsonDecoder",[190,240,212],{"class":204},[190,242,216],{"class":215},[190,244,219],{"class":204},[190,246,222],{"class":200},[190,248,225],{"class":204},[190,250,252],{"class":192,"line":251},3,[190,253,255],{"emptyLinePlaceholder":254},true,"\n",[190,257,259,261,264,266,269,272,275],{"class":192,"line":258},4,[190,260,197],{"class":196},[190,262,263],{"class":200}," wire ",[190,265,205],{"class":204},[190,267,268],{"class":208}," encode",[190,270,271],{"class":200},"(session)",[190,273,274],{"class":204},";",[190,276,278],{"class":277},"sHwdD"," \u002F\u002F a JSON string — Date and Map survive\n",[190,280,282,284,287,289,292,295,297],{"class":192,"line":281},5,[190,283,197],{"class":196},[190,285,286],{"class":200}," back ",[190,288,205],{"class":204},[190,290,291],{"class":208}," decode",[190,293,294],{"class":200},"(wire)",[190,296,274],{"class":204},[190,298,299],{"class":277}," \u002F\u002F Date is a Date again, Map is a Map again\n",[190,301,303],{"class":192,"line":302},6,[190,304,255],{"emptyLinePlaceholder":254},[190,306,308,311,314,317,320,323,325],{"class":192,"line":307},7,[190,309,310],{"class":200},"back",[190,312,313],{"class":204},".",[190,315,316],{"class":200},"startedAt ",[190,318,319],{"class":204},"instanceof",[190,321,322],{"class":215}," Date",[190,324,274],{"class":204},[190,326,327],{"class":277}," \u002F\u002F true\n",[190,329,331,333,335,338,340,343,345],{"class":192,"line":330},8,[190,332,310],{"class":200},[190,334,313],{"class":204},[190,336,337],{"class":200},"flags ",[190,339,319],{"class":204},[190,341,342],{"class":215}," Map",[190,344,274],{"class":204},[190,346,327],{"class":277},[138,348,349,350,352],{},"Here's the same data through plain ",[141,351,151],{},", for contrast:",[181,354,356],{"className":183,"code":355,"language":185,"meta":186,"style":186},"\u002F\u002F Plain JSON.stringify can't do this — your Date turns into a string and\n\u002F\u002F your Map turns into {} on the way out, and never comes back.\nJSON.stringify(session); \u002F\u002F {\"id\":\"s-1\",\"startedAt\":\"2026-01-01T...\",\"flags\":{}}\n",[141,357,358,363,368],{"__ignoreMap":186},[190,359,360],{"class":192,"line":193},[190,361,362],{"class":277},"\u002F\u002F Plain JSON.stringify can't do this — your Date turns into a string and\n",[190,364,365],{"class":192,"line":228},[190,366,367],{"class":277},"\u002F\u002F your Map turns into {} on the way out, and never comes back.\n",[190,369,370,373,375,378,380,382],{"class":192,"line":251},[190,371,372],{"class":200},"JSON",[190,374,313],{"class":204},[190,376,377],{"class":208},"stringify",[190,379,271],{"class":200},[190,381,274],{"class":204},[190,383,384],{"class":277}," \u002F\u002F {\"id\":\"s-1\",\"startedAt\":\"2026-01-01T...\",\"flags\":{}}\n",[386,387,389],"h3",{"id":388},"three-encoder-strategies","Three encoder strategies",[138,391,392,394,395,398],{},[141,393,143],{}," takes a ",[141,396,397],{},"strategy"," (a call-site literal) that decides how it walks your value and what it does with undeclared keys.",[181,400,402],{"className":183,"code":401,"language":185,"meta":186,"style":186},"\u002F\u002F 'clone' (default) — builds a fresh value from the declared shape, so\n\u002F\u002F undeclared keys are dropped for free. Never touches your input.\nconst encodeClean = createJsonEncoder\u003CProfile>({strategy: 'clone'});\n\n\u002F\u002F 'mutate' — transforms leaves in place (no clone), and KEEPS undeclared keys\n\u002F\u002F on the wire. Fastest, but it mutates the object you pass in.\nconst encodeFast = createJsonEncoder\u003CProfile>({strategy: 'mutate'});\n\n\u002F\u002F 'direct' — single pass, no clone, always strips undeclared keys.\nconst encodeDirect = createJsonEncoder\u003CProfile>({strategy: 'direct'});\n",[141,403,404,409,414,462,466,471,476,514,518,524],{"__ignoreMap":186},[190,405,406],{"class":192,"line":193},[190,407,408],{"class":277},"\u002F\u002F 'clone' (default) — builds a fresh value from the declared shape, so\n",[190,410,411],{"class":192,"line":228},[190,412,413],{"class":277},"\u002F\u002F undeclared keys are dropped for free. Never touches your input.\n",[190,415,416,418,421,423,425,427,430,432,435,438,441,444,447,451,454,457,460],{"class":192,"line":251},[190,417,197],{"class":196},[190,419,420],{"class":200}," encodeClean ",[190,422,205],{"class":204},[190,424,209],{"class":208},[190,426,212],{"class":204},[190,428,429],{"class":215},"Profile",[190,431,219],{"class":204},[190,433,434],{"class":200},"(",[190,436,437],{"class":204},"{",[190,439,397],{"class":440},"swJcz",[190,442,443],{"class":204},":",[190,445,446],{"class":204}," '",[190,448,450],{"class":449},"sfazB","clone",[190,452,453],{"class":204},"'",[190,455,456],{"class":204},"}",[190,458,459],{"class":200},")",[190,461,225],{"class":204},[190,463,464],{"class":192,"line":258},[190,465,255],{"emptyLinePlaceholder":254},[190,467,468],{"class":192,"line":281},[190,469,470],{"class":277},"\u002F\u002F 'mutate' — transforms leaves in place (no clone), and KEEPS undeclared keys\n",[190,472,473],{"class":192,"line":302},[190,474,475],{"class":277},"\u002F\u002F on the wire. Fastest, but it mutates the object you pass in.\n",[190,477,478,480,483,485,487,489,491,493,495,497,499,501,503,506,508,510,512],{"class":192,"line":307},[190,479,197],{"class":196},[190,481,482],{"class":200}," encodeFast ",[190,484,205],{"class":204},[190,486,209],{"class":208},[190,488,212],{"class":204},[190,490,429],{"class":215},[190,492,219],{"class":204},[190,494,434],{"class":200},[190,496,437],{"class":204},[190,498,397],{"class":440},[190,500,443],{"class":204},[190,502,446],{"class":204},[190,504,505],{"class":449},"mutate",[190,507,453],{"class":204},[190,509,456],{"class":204},[190,511,459],{"class":200},[190,513,225],{"class":204},[190,515,516],{"class":192,"line":330},[190,517,255],{"emptyLinePlaceholder":254},[190,519,521],{"class":192,"line":520},9,[190,522,523],{"class":277},"\u002F\u002F 'direct' — single pass, no clone, always strips undeclared keys.\n",[190,525,527,529,532,534,536,538,540,542,544,546,548,550,552,555,557,559,561],{"class":192,"line":526},10,[190,528,197],{"class":196},[190,530,531],{"class":200}," encodeDirect ",[190,533,205],{"class":204},[190,535,209],{"class":208},[190,537,212],{"class":204},[190,539,429],{"class":215},[190,541,219],{"class":204},[190,543,434],{"class":200},[190,545,437],{"class":204},[190,547,397],{"class":440},[190,549,443],{"class":204},[190,551,446],{"class":204},[190,553,554],{"class":449},"direct",[190,556,453],{"class":204},[190,558,456],{"class":204},[190,560,459],{"class":200},[190,562,225],{"class":204},[138,564,565],{},"Each one compiles to a different specialized function. The JSON that comes out is the same, but the work behind it is very different:",[567,568,569,588],"table",{},[570,571,572],"thead",{},[573,574,575,579,582,585],"tr",{},[576,577,578],"th",{},"Strategy",[576,580,581],{},"Under the hood",[576,583,584],{},"Mutates input?",[576,586,587],{},"Undeclared keys",[589,590,591,612,635],"tbody",{},[573,592,593,603,606,609],{},[594,595,596,598,599],"td",{},[141,597,450],{}," ",[600,601,602],"em",{},"(default)",[594,604,605],{},"Builds a fresh, JSON-safe value from the declared shape, then encodes that. It's safe and never touches your input, but cloning every object costs a little more memory.",[594,607,608],{},"No",[594,610,611],{},"Dropped (for free)",[573,613,614,618,626,632],{},[594,615,616],{},[141,617,505],{},[594,619,620,621,170,623,625],{},"Rewrites non-serializable leaves (",[141,622,159],{},[141,624,173],{},", …) in place to make the value JSON-ready, then encodes it. Way faster with zero allocation, at the cost of mutating the object you pass in.",[594,627,628],{},[629,630,631],"strong",{},"Yes",[594,633,634],{},"Kept on the wire",[573,636,637,641,649,651],{},[594,638,639],{},[141,640,554],{},[594,642,643,644,646,647,313],{},"A purpose-built ",[141,645,151],{},": one pass that iterates every field and writes valid JSON straight out. No clone, so it's lighter on memory than ",[141,648,450],{},[594,650,608],{},[594,652,653],{},"Dropped",[655,656,657,659,660,662],"tip",{},[141,658,450],{}," is the safe default. It never touches your input and drops stray keys by building a fresh value from the type. Reach for ",[141,661,505],{}," only in a hot path where the allocation shows up in a profile, and you're fine mutating the object you pass in.",[133,664,666],{"id":665},"binary-encode-decode","Binary encode \u002F decode",[138,668,669,144,672,675,676,679,680,682],{},[141,670,671],{},"createBinaryEncoder",[141,673,674],{},"createBinaryDecoder"," are the same idea, smaller and faster on the wire. The encoder returns an ",[141,677,678],{},"ArrayBuffer","; the decoder takes one back. Like JSON, the codec knows your type, so a ",[141,681,159],{}," round-trips cleanly.",[181,684,686],{"className":183,"code":685,"language":185,"meta":186,"style":186},"const encode = createBinaryEncoder\u003CTelemetry>();\nconst decode = createBinaryDecoder\u003CTelemetry>();\n\nconst bytes = encode(sample); \u002F\u002F an ArrayBuffer — compact, no field names on the wire\nconst back = decode(bytes); \u002F\u002F typed as DataOnly\u003CTelemetry>\n\nback.recordedAt instanceof Date; \u002F\u002F true — Date round-trips, like JSON\n",[141,687,688,710,731,735,754,772,776],{"__ignoreMap":186},[190,689,690,692,694,696,699,701,704,706,708],{"class":192,"line":193},[190,691,197],{"class":196},[190,693,201],{"class":200},[190,695,205],{"class":204},[190,697,698],{"class":208}," createBinaryEncoder",[190,700,212],{"class":204},[190,702,703],{"class":215},"Telemetry",[190,705,219],{"class":204},[190,707,222],{"class":200},[190,709,225],{"class":204},[190,711,712,714,716,718,721,723,725,727,729],{"class":192,"line":228},[190,713,197],{"class":196},[190,715,233],{"class":200},[190,717,205],{"class":204},[190,719,720],{"class":208}," createBinaryDecoder",[190,722,212],{"class":204},[190,724,703],{"class":215},[190,726,219],{"class":204},[190,728,222],{"class":200},[190,730,225],{"class":204},[190,732,733],{"class":192,"line":251},[190,734,255],{"emptyLinePlaceholder":254},[190,736,737,739,742,744,746,749,751],{"class":192,"line":258},[190,738,197],{"class":196},[190,740,741],{"class":200}," bytes ",[190,743,205],{"class":204},[190,745,268],{"class":208},[190,747,748],{"class":200},"(sample)",[190,750,274],{"class":204},[190,752,753],{"class":277}," \u002F\u002F an ArrayBuffer — compact, no field names on the wire\n",[190,755,756,758,760,762,764,767,769],{"class":192,"line":281},[190,757,197],{"class":196},[190,759,286],{"class":200},[190,761,205],{"class":204},[190,763,291],{"class":208},[190,765,766],{"class":200},"(bytes)",[190,768,274],{"class":204},[190,770,771],{"class":277}," \u002F\u002F typed as DataOnly\u003CTelemetry>\n",[190,773,774],{"class":192,"line":302},[190,775,255],{"emptyLinePlaceholder":254},[190,777,778,780,782,785,787,789,791],{"class":192,"line":307},[190,779,310],{"class":200},[190,781,313],{"class":204},[190,783,784],{"class":200},"recordedAt ",[190,786,319],{"class":204},[190,788,322],{"class":215},[190,790,274],{"class":204},[190,792,793],{"class":277}," \u002F\u002F true — Date round-trips, like JSON\n",[138,795,796,797,800],{},"Reach for binary when you're moving lots of records and both ends are yours (WebSockets, game state, IoT). Stick with JSON when a human or a third party reads the payload, or you need it ",[141,798,799],{},"curl","-able.",[386,802,804],{"id":803},"reuse-the-buffer-in-hot-loops","Reuse the buffer in hot loops",[138,806,807,808,811,812,815,816,819],{},"By default each encode allocates a fresh backing buffer. In a tight loop that adds up, so build a ",[141,809,810],{},"DataViewSerializer"," once with ",[141,813,814],{},"createDataViewSerializer"," and hand it to the encoder to reuse the same buffer. ",[141,817,818],{},"createDataViewDeserializer"," does the same on the way back.",[181,821,823],{"className":183,"code":822,"language":185,"meta":186,"style":186},"\u002F\u002F In a hot loop, build the serializer once and hand it to the encoder so it\n\u002F\u002F reuses the same backing buffer instead of allocating a fresh one each call.\nconst ser = createDataViewSerializer('ticks');\nconst ticks: Tick[] = [\n  {symbol: 'TS', price: 7},\n  {symbol: 'GO', price: 9},\n];\n\nconst buffers = ticks.map((tick) => encode(tick, ser)); \u002F\u002F writes into the shared serializer\n\n\u002F\u002F Same idea on the way back — reuse a deserializer for a known buffer.\nconst des = createDataViewDeserializer('ticks', buffers[0]);\nconst firstTick = decode(des);\n",[141,824,825,830,835,860,880,912,938,945,949,993,997,1003,1037],{"__ignoreMap":186},[190,826,827],{"class":192,"line":193},[190,828,829],{"class":277},"\u002F\u002F In a hot loop, build the serializer once and hand it to the encoder so it\n",[190,831,832],{"class":192,"line":228},[190,833,834],{"class":277},"\u002F\u002F reuses the same backing buffer instead of allocating a fresh one each call.\n",[190,836,837,839,842,844,847,849,851,854,856,858],{"class":192,"line":251},[190,838,197],{"class":196},[190,840,841],{"class":200}," ser ",[190,843,205],{"class":204},[190,845,846],{"class":208}," createDataViewSerializer",[190,848,434],{"class":200},[190,850,453],{"class":204},[190,852,853],{"class":449},"ticks",[190,855,453],{"class":204},[190,857,459],{"class":200},[190,859,225],{"class":204},[190,861,862,864,867,869,872,875,877],{"class":192,"line":258},[190,863,197],{"class":196},[190,865,866],{"class":200}," ticks",[190,868,443],{"class":204},[190,870,871],{"class":215}," Tick",[190,873,874],{"class":200},"[] ",[190,876,205],{"class":204},[190,878,879],{"class":200}," [\n",[190,881,882,885,888,890,892,895,897,900,903,905,909],{"class":192,"line":281},[190,883,884],{"class":204},"  {",[190,886,887],{"class":440},"symbol",[190,889,443],{"class":204},[190,891,446],{"class":204},[190,893,894],{"class":449},"TS",[190,896,453],{"class":204},[190,898,899],{"class":204},",",[190,901,902],{"class":440}," price",[190,904,443],{"class":204},[190,906,908],{"class":907},"sbssI"," 7",[190,910,911],{"class":204},"},\n",[190,913,914,916,918,920,922,925,927,929,931,933,936],{"class":192,"line":302},[190,915,884],{"class":204},[190,917,887],{"class":440},[190,919,443],{"class":204},[190,921,446],{"class":204},[190,923,924],{"class":449},"GO",[190,926,453],{"class":204},[190,928,899],{"class":204},[190,930,902],{"class":440},[190,932,443],{"class":204},[190,934,935],{"class":907}," 9",[190,937,911],{"class":204},[190,939,940,943],{"class":192,"line":307},[190,941,942],{"class":200},"]",[190,944,225],{"class":204},[190,946,947],{"class":192,"line":330},[190,948,255],{"emptyLinePlaceholder":254},[190,950,951,953,956,958,960,962,965,967,969,973,975,978,980,983,985,988,990],{"class":192,"line":520},[190,952,197],{"class":196},[190,954,955],{"class":200}," buffers ",[190,957,205],{"class":204},[190,959,866],{"class":200},[190,961,313],{"class":204},[190,963,964],{"class":208},"map",[190,966,434],{"class":200},[190,968,434],{"class":204},[190,970,972],{"class":971},"sHdIc","tick",[190,974,459],{"class":204},[190,976,977],{"class":196}," =>",[190,979,268],{"class":208},[190,981,982],{"class":200},"(tick",[190,984,899],{"class":204},[190,986,987],{"class":200}," ser))",[190,989,274],{"class":204},[190,991,992],{"class":277}," \u002F\u002F writes into the shared serializer\n",[190,994,995],{"class":192,"line":526},[190,996,255],{"emptyLinePlaceholder":254},[190,998,1000],{"class":192,"line":999},11,[190,1001,1002],{"class":277},"\u002F\u002F Same idea on the way back — reuse a deserializer for a known buffer.\n",[190,1004,1006,1008,1011,1013,1016,1018,1020,1022,1024,1026,1029,1032,1035],{"class":192,"line":1005},12,[190,1007,197],{"class":196},[190,1009,1010],{"class":200}," des ",[190,1012,205],{"class":204},[190,1014,1015],{"class":208}," createDataViewDeserializer",[190,1017,434],{"class":200},[190,1019,453],{"class":204},[190,1021,853],{"class":449},[190,1023,453],{"class":204},[190,1025,899],{"class":204},[190,1027,1028],{"class":200}," buffers[",[190,1030,1031],{"class":907},"0",[190,1033,1034],{"class":200},"])",[190,1036,225],{"class":204},[190,1038,1040,1042,1045,1047,1049,1052],{"class":192,"line":1039},13,[190,1041,197],{"class":196},[190,1043,1044],{"class":200}," firstTick ",[190,1046,205],{"class":204},[190,1048,291],{"class":208},[190,1050,1051],{"class":200},"(des)",[190,1053,225],{"class":204},[1055,1056,1057,1058,144,1060,1062],"note",{},"You only need these helpers for buffer reuse in performance-sensitive code. For everyday encode\u002Fdecode, the plain ",[141,1059,671],{},[141,1061,674],{}," calls handle their own buffers.",[133,1064,1066],{"id":1065},"custom-class-serializers","Custom class serializers",[138,1068,1069,1070,170,1072,170,1074,170,1076,1079,1080,144,1083,1086,1087,1092],{},"Plain objects are handled for you, and the built-in classes (",[141,1071,159],{},[141,1073,166],{},[141,1075,178],{},[141,1077,1078],{},"RegExp",") round-trip for free. Your own class, though? The build can't know how to serialize it, so register a ",[141,1081,1082],{},"serialize",[141,1084,1085],{},"deserialize"," pair with ",[629,1088,1089],{},[141,1090,1091],{},"registerClassSerializer",", keyed by the class name.",[181,1094,1096],{"className":183,"code":1095,"language":185,"meta":186,"style":186},"import {registerClassSerializer, createJsonEncoder, createJsonDecoder} from 'ts-runtypes';\n\n\u002F\u002F Your own class. ts-runtypes can't guess how to put it on the wire, so\n\u002F\u002F you teach it once: a serialize\u002Fdeserialize pair keyed by the class name.\nclass Money {\n  constructor(\n    public amount: number,\n    public currency: string\n  ) {}\n}\n\nregisterClassSerializer\u003CMoney>('Money', {\n  \u002F\u002F instance -> JSON-ready data (the pipeline stringifies this for you)\n  serialize: (m) => `${m.amount} ${m.currency}`,\n  \u002F\u002F parsed data -> rebuilt instance\n  deserialize: (data) => {\n    const [amount, currency] = String(data).split(' ');\n    return new Money(Number(amount), currency);\n  },\n});\n\ntype Invoice = {id: string; total: Money};\n\nconst encode = createJsonEncoder\u003CInvoice>();\nconst decode = createJsonDecoder\u003CInvoice>();\n\nconst json = encode({id: 'inv_1', total: new Money(4999, 'USD')});\nconst back = decode(json); \u002F\u002F back.total is a real Money instance again\n\nexport {Money, encode, decode, back};\nexport type {Invoice};\n",[141,1097,1098,1131,1135,1140,1145,1156,1164,1180,1192,1200,1205,1209,1232,1237,1282,1288,1307,1351,1381,1387,1396,1401,1434,1439,1461,1482,1487,1546,1565,1570,1595],{"__ignoreMap":186},[190,1099,1100,1104,1107,1109,1111,1113,1115,1117,1119,1122,1124,1127,1129],{"class":192,"line":193},[190,1101,1103],{"class":1102},"s7zQu","import",[190,1105,1106],{"class":204}," {",[190,1108,1091],{"class":200},[190,1110,899],{"class":204},[190,1112,209],{"class":200},[190,1114,899],{"class":204},[190,1116,238],{"class":200},[190,1118,456],{"class":204},[190,1120,1121],{"class":1102}," from",[190,1123,446],{"class":204},[190,1125,1126],{"class":449},"ts-runtypes",[190,1128,453],{"class":204},[190,1130,225],{"class":204},[190,1132,1133],{"class":192,"line":228},[190,1134,255],{"emptyLinePlaceholder":254},[190,1136,1137],{"class":192,"line":251},[190,1138,1139],{"class":277},"\u002F\u002F Your own class. ts-runtypes can't guess how to put it on the wire, so\n",[190,1141,1142],{"class":192,"line":258},[190,1143,1144],{"class":277},"\u002F\u002F you teach it once: a serialize\u002Fdeserialize pair keyed by the class name.\n",[190,1146,1147,1150,1153],{"class":192,"line":281},[190,1148,1149],{"class":196},"class",[190,1151,1152],{"class":215}," Money",[190,1154,1155],{"class":204}," {\n",[190,1157,1158,1161],{"class":192,"line":302},[190,1159,1160],{"class":196},"  constructor",[190,1162,1163],{"class":204},"(\n",[190,1165,1166,1169,1172,1174,1177],{"class":192,"line":307},[190,1167,1168],{"class":196},"    public",[190,1170,1171],{"class":971}," amount",[190,1173,443],{"class":204},[190,1175,1176],{"class":215}," number",[190,1178,1179],{"class":204},",\n",[190,1181,1182,1184,1187,1189],{"class":192,"line":330},[190,1183,1168],{"class":196},[190,1185,1186],{"class":971}," currency",[190,1188,443],{"class":204},[190,1190,1191],{"class":215}," string\n",[190,1193,1194,1197],{"class":192,"line":520},[190,1195,1196],{"class":204},"  )",[190,1198,1199],{"class":204}," {}\n",[190,1201,1202],{"class":192,"line":526},[190,1203,1204],{"class":204},"}\n",[190,1206,1207],{"class":192,"line":999},[190,1208,255],{"emptyLinePlaceholder":254},[190,1210,1211,1213,1215,1218,1220,1222,1224,1226,1228,1230],{"class":192,"line":1005},[190,1212,1091],{"class":208},[190,1214,212],{"class":204},[190,1216,1217],{"class":215},"Money",[190,1219,219],{"class":204},[190,1221,434],{"class":200},[190,1223,453],{"class":204},[190,1225,1217],{"class":449},[190,1227,453],{"class":204},[190,1229,899],{"class":204},[190,1231,1155],{"class":204},[190,1233,1234],{"class":192,"line":1039},[190,1235,1236],{"class":277},"  \u002F\u002F instance -> JSON-ready data (the pipeline stringifies this for you)\n",[190,1238,1240,1243,1245,1248,1251,1253,1255,1258,1260,1262,1265,1267,1270,1272,1274,1277,1280],{"class":192,"line":1239},14,[190,1241,1242],{"class":208},"  serialize",[190,1244,443],{"class":204},[190,1246,1247],{"class":204}," (",[190,1249,1250],{"class":971},"m",[190,1252,459],{"class":204},[190,1254,977],{"class":196},[190,1256,1257],{"class":204}," `${",[190,1259,1250],{"class":200},[190,1261,313],{"class":204},[190,1263,1264],{"class":200},"amount",[190,1266,456],{"class":204},[190,1268,1269],{"class":204}," ${",[190,1271,1250],{"class":200},[190,1273,313],{"class":204},[190,1275,1276],{"class":200},"currency",[190,1278,1279],{"class":204},"}`",[190,1281,1179],{"class":204},[190,1283,1285],{"class":192,"line":1284},15,[190,1286,1287],{"class":277},"  \u002F\u002F parsed data -> rebuilt instance\n",[190,1289,1291,1294,1296,1298,1301,1303,1305],{"class":192,"line":1290},16,[190,1292,1293],{"class":208},"  deserialize",[190,1295,443],{"class":204},[190,1297,1247],{"class":204},[190,1299,1300],{"class":971},"data",[190,1302,459],{"class":204},[190,1304,977],{"class":196},[190,1306,1155],{"class":204},[190,1308,1310,1313,1316,1318,1320,1322,1324,1327,1330,1332,1334,1336,1338,1341,1343,1345,1347,1349],{"class":192,"line":1309},17,[190,1311,1312],{"class":196},"    const",[190,1314,1315],{"class":204}," [",[190,1317,1264],{"class":200},[190,1319,899],{"class":204},[190,1321,1186],{"class":200},[190,1323,942],{"class":204},[190,1325,1326],{"class":204}," =",[190,1328,1329],{"class":208}," String",[190,1331,434],{"class":440},[190,1333,1300],{"class":200},[190,1335,459],{"class":440},[190,1337,313],{"class":204},[190,1339,1340],{"class":208},"split",[190,1342,434],{"class":440},[190,1344,453],{"class":204},[190,1346,446],{"class":204},[190,1348,459],{"class":440},[190,1350,225],{"class":204},[190,1352,1354,1357,1360,1362,1364,1367,1369,1371,1373,1375,1377,1379],{"class":192,"line":1353},18,[190,1355,1356],{"class":1102},"    return",[190,1358,1359],{"class":204}," new",[190,1361,1152],{"class":208},[190,1363,434],{"class":440},[190,1365,1366],{"class":208},"Number",[190,1368,434],{"class":440},[190,1370,1264],{"class":200},[190,1372,459],{"class":440},[190,1374,899],{"class":204},[190,1376,1186],{"class":200},[190,1378,459],{"class":440},[190,1380,225],{"class":204},[190,1382,1384],{"class":192,"line":1383},19,[190,1385,1386],{"class":204},"  },\n",[190,1388,1390,1392,1394],{"class":192,"line":1389},20,[190,1391,456],{"class":204},[190,1393,459],{"class":200},[190,1395,225],{"class":204},[190,1397,1399],{"class":192,"line":1398},21,[190,1400,255],{"emptyLinePlaceholder":254},[190,1402,1404,1407,1410,1412,1414,1417,1419,1422,1424,1427,1429,1431],{"class":192,"line":1403},22,[190,1405,1406],{"class":196},"type",[190,1408,1409],{"class":215}," Invoice",[190,1411,1326],{"class":204},[190,1413,1106],{"class":204},[190,1415,1416],{"class":440},"id",[190,1418,443],{"class":204},[190,1420,1421],{"class":215}," string",[190,1423,274],{"class":204},[190,1425,1426],{"class":440}," total",[190,1428,443],{"class":204},[190,1430,1152],{"class":215},[190,1432,1433],{"class":204},"};\n",[190,1435,1437],{"class":192,"line":1436},23,[190,1438,255],{"emptyLinePlaceholder":254},[190,1440,1442,1444,1446,1448,1450,1452,1455,1457,1459],{"class":192,"line":1441},24,[190,1443,197],{"class":196},[190,1445,201],{"class":200},[190,1447,205],{"class":204},[190,1449,209],{"class":208},[190,1451,212],{"class":204},[190,1453,1454],{"class":215},"Invoice",[190,1456,219],{"class":204},[190,1458,222],{"class":200},[190,1460,225],{"class":204},[190,1462,1464,1466,1468,1470,1472,1474,1476,1478,1480],{"class":192,"line":1463},25,[190,1465,197],{"class":196},[190,1467,233],{"class":200},[190,1469,205],{"class":204},[190,1471,238],{"class":208},[190,1473,212],{"class":204},[190,1475,1454],{"class":215},[190,1477,219],{"class":204},[190,1479,222],{"class":200},[190,1481,225],{"class":204},[190,1483,1485],{"class":192,"line":1484},26,[190,1486,255],{"emptyLinePlaceholder":254},[190,1488,1490,1492,1495,1497,1499,1501,1503,1505,1507,1509,1512,1514,1516,1518,1520,1522,1524,1526,1529,1531,1533,1536,1538,1540,1542,1544],{"class":192,"line":1489},27,[190,1491,197],{"class":196},[190,1493,1494],{"class":200}," json ",[190,1496,205],{"class":204},[190,1498,268],{"class":208},[190,1500,434],{"class":200},[190,1502,437],{"class":204},[190,1504,1416],{"class":440},[190,1506,443],{"class":204},[190,1508,446],{"class":204},[190,1510,1511],{"class":449},"inv_1",[190,1513,453],{"class":204},[190,1515,899],{"class":204},[190,1517,1426],{"class":440},[190,1519,443],{"class":204},[190,1521,1359],{"class":204},[190,1523,1152],{"class":208},[190,1525,434],{"class":200},[190,1527,1528],{"class":907},"4999",[190,1530,899],{"class":204},[190,1532,446],{"class":204},[190,1534,1535],{"class":449},"USD",[190,1537,453],{"class":204},[190,1539,459],{"class":200},[190,1541,456],{"class":204},[190,1543,459],{"class":200},[190,1545,225],{"class":204},[190,1547,1549,1551,1553,1555,1557,1560,1562],{"class":192,"line":1548},28,[190,1550,197],{"class":196},[190,1552,286],{"class":200},[190,1554,205],{"class":204},[190,1556,291],{"class":208},[190,1558,1559],{"class":200},"(json)",[190,1561,274],{"class":204},[190,1563,1564],{"class":277}," \u002F\u002F back.total is a real Money instance again\n",[190,1566,1568],{"class":192,"line":1567},29,[190,1569,255],{"emptyLinePlaceholder":254},[190,1571,1573,1576,1578,1580,1582,1584,1586,1588,1590,1593],{"class":192,"line":1572},30,[190,1574,1575],{"class":1102},"export",[190,1577,1106],{"class":204},[190,1579,1217],{"class":200},[190,1581,899],{"class":204},[190,1583,268],{"class":200},[190,1585,899],{"class":204},[190,1587,291],{"class":200},[190,1589,899],{"class":204},[190,1591,1592],{"class":200}," back",[190,1594,1433],{"class":204},[190,1596,1598,1600,1603,1605,1607],{"class":192,"line":1597},31,[190,1599,1575],{"class":1102},[190,1601,1602],{"class":1102}," type",[190,1604,1106],{"class":204},[190,1606,1454],{"class":200},[190,1608,1433],{"class":204},[138,1610,1611,1613,1614,1616],{},[141,1612,1082],{}," turns an instance into JSON-ready data; ",[141,1615,1085],{}," rebuilds it from the parsed value after the round-trip. Register before anything serializes the class.",[1055,1618,1619,1620,1623,1624,1627],{},"This only affects JSON and binary. ",[141,1621,1622],{},"createValidate"," always checks a class by its structural shape and never routes through the serializer. Without a registered serializer, the build falls back to the structural shape and emits a ",[141,1625,1626],{},"CLS001"," Warning pointing you here.",[133,1629,1631],{"id":1630},"circular-references","Circular references",[138,1633,1634,1635,1638,1639,1642,1643,160,1645,1647,1648,1651,1652,1655,1656,1658],{},"The generated encoders are fast precisely ",[600,1636,1637],{},"because"," they don't track which objects they've already seen. A runtime value that points back at itself (",[141,1640,1641],{},"a.next = a",") makes them recurse until the stack overflows. Both ",[141,1644,143],{},[141,1646,671],{}," accept a per-call ",[141,1649,1650],{},"rejectCircularRefs"," option that guards that encoder. Instead of recursing, it throws a ",[141,1653,1654],{},"CircularReferenceError"," carrying the path to the cycle, the same idea as ",[141,1657,151],{},"'s own cycle error.",[181,1660,1662],{"className":183,"code":1661,"language":185,"meta":186,"style":186},"\u002F\u002F Arm the guard for THIS encoder only. The encoder throws a\n\u002F\u002F `CircularReferenceError` instead of recursing forever.\nconst encode = createJsonEncoder\u003CNode>(undefined, {rejectCircularRefs: true});\n\ntry {\n  encode(cyclic as Node);\n} catch (err) {\n  err instanceof CircularReferenceError; \u002F\u002F true\n  (err as CircularReferenceError).path; \u002F\u002F ['next'] — where the back-edge was found\n}\n",[141,1663,1664,1669,1674,1712,1716,1723,1743,1756,1771,1795],{"__ignoreMap":186},[190,1665,1666],{"class":192,"line":193},[190,1667,1668],{"class":277},"\u002F\u002F Arm the guard for THIS encoder only. The encoder throws a\n",[190,1670,1671],{"class":192,"line":228},[190,1672,1673],{"class":277},"\u002F\u002F `CircularReferenceError` instead of recursing forever.\n",[190,1675,1676,1678,1680,1682,1684,1686,1689,1691,1693,1696,1698,1700,1702,1706,1708,1710],{"class":192,"line":251},[190,1677,197],{"class":196},[190,1679,201],{"class":200},[190,1681,205],{"class":204},[190,1683,209],{"class":208},[190,1685,212],{"class":204},[190,1687,1688],{"class":215},"Node",[190,1690,219],{"class":204},[190,1692,434],{"class":200},[190,1694,1695],{"class":204},"undefined,",[190,1697,1106],{"class":204},[190,1699,1650],{"class":440},[190,1701,443],{"class":204},[190,1703,1705],{"class":1704},"sfNiH"," true",[190,1707,456],{"class":204},[190,1709,459],{"class":200},[190,1711,225],{"class":204},[190,1713,1714],{"class":192,"line":258},[190,1715,255],{"emptyLinePlaceholder":254},[190,1717,1718,1721],{"class":192,"line":281},[190,1719,1720],{"class":1102},"try",[190,1722,1155],{"class":204},[190,1724,1725,1728,1730,1733,1736,1739,1741],{"class":192,"line":302},[190,1726,1727],{"class":208},"  encode",[190,1729,434],{"class":440},[190,1731,1732],{"class":200},"cyclic",[190,1734,1735],{"class":1102}," as",[190,1737,1738],{"class":215}," Node",[190,1740,459],{"class":440},[190,1742,225],{"class":204},[190,1744,1745,1747,1750,1753],{"class":192,"line":307},[190,1746,456],{"class":204},[190,1748,1749],{"class":1102}," catch",[190,1751,1752],{"class":200}," (err) ",[190,1754,1755],{"class":204},"{\n",[190,1757,1758,1761,1764,1767,1769],{"class":192,"line":330},[190,1759,1760],{"class":200},"  err",[190,1762,1763],{"class":204}," instanceof",[190,1765,1766],{"class":215}," CircularReferenceError",[190,1768,274],{"class":204},[190,1770,327],{"class":277},[190,1772,1773,1776,1779,1781,1783,1785,1787,1790,1792],{"class":192,"line":520},[190,1774,1775],{"class":440},"  (",[190,1777,1778],{"class":200},"err",[190,1780,1735],{"class":1102},[190,1782,1766],{"class":215},[190,1784,459],{"class":440},[190,1786,313],{"class":204},[190,1788,1789],{"class":200},"path",[190,1791,274],{"class":204},[190,1793,1794],{"class":277}," \u002F\u002F ['next'] — where the back-edge was found\n",[190,1796,1797],{"class":192,"line":526},[190,1798,1204],{"class":204},[138,1800,1801,1802,1807,1808,313],{},"Rather than tagging every encoder one by one, you can arm the guard process-wide with ",[629,1803,1804],{},[141,1805,1806],{},"setRejectCircularRefs(true)",". Every guarded factory will check from then on, and any individual call can opt out with ",[141,1809,1810],{},"{rejectCircularRefs: false}",[181,1812,1814],{"className":183,"code":1813,"language":185,"meta":186,"style":186},"\u002F\u002F Or arm it once globally — every guarded factory (validate, getValidationErrors,\n\u002F\u002F JSON encoder, binary encoder) checks unless given `{rejectCircularRefs: false}`.\nsetRejectCircularRefs(true);\n\nconst encodeBin = createBinaryEncoder\u003CNode>(); \u002F\u002F armed via the global flag\ntry {\n  encodeBin(cyclic as Node);\n} catch (err) {\n  err instanceof CircularReferenceError; \u002F\u002F true\n}\n\nsetRejectCircularRefs(false); \u002F\u002F disarm — back to the default\n",[141,1815,1816,1821,1826,1840,1844,1868,1874,1891,1901,1913,1917,1921],{"__ignoreMap":186},[190,1817,1818],{"class":192,"line":193},[190,1819,1820],{"class":277},"\u002F\u002F Or arm it once globally — every guarded factory (validate, getValidationErrors,\n",[190,1822,1823],{"class":192,"line":228},[190,1824,1825],{"class":277},"\u002F\u002F JSON encoder, binary encoder) checks unless given `{rejectCircularRefs: false}`.\n",[190,1827,1828,1831,1833,1836,1838],{"class":192,"line":251},[190,1829,1830],{"class":208},"setRejectCircularRefs",[190,1832,434],{"class":200},[190,1834,1835],{"class":1704},"true",[190,1837,459],{"class":200},[190,1839,225],{"class":204},[190,1841,1842],{"class":192,"line":258},[190,1843,255],{"emptyLinePlaceholder":254},[190,1845,1846,1848,1851,1853,1855,1857,1859,1861,1863,1865],{"class":192,"line":281},[190,1847,197],{"class":196},[190,1849,1850],{"class":200}," encodeBin ",[190,1852,205],{"class":204},[190,1854,698],{"class":208},[190,1856,212],{"class":204},[190,1858,1688],{"class":215},[190,1860,219],{"class":204},[190,1862,222],{"class":200},[190,1864,274],{"class":204},[190,1866,1867],{"class":277}," \u002F\u002F armed via the global flag\n",[190,1869,1870,1872],{"class":192,"line":302},[190,1871,1720],{"class":1102},[190,1873,1155],{"class":204},[190,1875,1876,1879,1881,1883,1885,1887,1889],{"class":192,"line":307},[190,1877,1878],{"class":208},"  encodeBin",[190,1880,434],{"class":440},[190,1882,1732],{"class":200},[190,1884,1735],{"class":1102},[190,1886,1738],{"class":215},[190,1888,459],{"class":440},[190,1890,225],{"class":204},[190,1892,1893,1895,1897,1899],{"class":192,"line":330},[190,1894,456],{"class":204},[190,1896,1749],{"class":1102},[190,1898,1752],{"class":200},[190,1900,1755],{"class":204},[190,1902,1903,1905,1907,1909,1911],{"class":192,"line":520},[190,1904,1760],{"class":200},[190,1906,1763],{"class":204},[190,1908,1766],{"class":215},[190,1910,274],{"class":204},[190,1912,327],{"class":277},[190,1914,1915],{"class":192,"line":526},[190,1916,1204],{"class":204},[190,1918,1919],{"class":192,"line":999},[190,1920,255],{"emptyLinePlaceholder":254},[190,1922,1923,1925,1927,1930,1932,1934],{"class":192,"line":1005},[190,1924,1830],{"class":208},[190,1926,434],{"class":200},[190,1928,1929],{"class":1704},"false",[190,1931,459],{"class":200},[190,1933,274],{"class":204},[190,1935,1936],{"class":277}," \u002F\u002F disarm — back to the default\n",[138,1938,1939,1940,1943],{},"The check is ",[629,1941,1942],{},"pay-for-use",": types that can't cycle don't get wrapped at all, even with the global flag on. And only real cycles trigger it. A value shared between two siblings walks through fine, because the guard only watches the current path down, not every object it ever saw.",[181,1945,1947],{"className":183,"code":1946,"language":185,"meta":186,"style":186},"\u002F\u002F Shared-but-acyclic values pass — `shared` is reached twice, but never\n\u002F\u002F through itself, so the guard stays quiet.\nconst shared: Node = {name: 'shared'};\nconst dag: Node[] = [\n  {name: 'root', next: shared},\n  {name: 'alt', next: shared},\n];\n\nconst encodeList = createJsonEncoder\u003CNode[]>(undefined, {rejectCircularRefs: true});\nencodeList(dag); \u002F\u002F encodes normally — no cycle\n",[141,1948,1949,1954,1959,1988,2005,2031,2056,2062,2066,2104],{"__ignoreMap":186},[190,1950,1951],{"class":192,"line":193},[190,1952,1953],{"class":277},"\u002F\u002F Shared-but-acyclic values pass — `shared` is reached twice, but never\n",[190,1955,1956],{"class":192,"line":228},[190,1957,1958],{"class":277},"\u002F\u002F through itself, so the guard stays quiet.\n",[190,1960,1961,1963,1966,1968,1970,1972,1974,1977,1979,1981,1984,1986],{"class":192,"line":251},[190,1962,197],{"class":196},[190,1964,1965],{"class":200}," shared",[190,1967,443],{"class":204},[190,1969,1738],{"class":215},[190,1971,1326],{"class":204},[190,1973,1106],{"class":204},[190,1975,1976],{"class":440},"name",[190,1978,443],{"class":204},[190,1980,446],{"class":204},[190,1982,1983],{"class":449},"shared",[190,1985,453],{"class":204},[190,1987,1433],{"class":204},[190,1989,1990,1992,1995,1997,1999,2001,2003],{"class":192,"line":258},[190,1991,197],{"class":196},[190,1993,1994],{"class":200}," dag",[190,1996,443],{"class":204},[190,1998,1738],{"class":215},[190,2000,874],{"class":200},[190,2002,205],{"class":204},[190,2004,879],{"class":200},[190,2006,2007,2009,2011,2013,2015,2018,2020,2022,2025,2027,2029],{"class":192,"line":281},[190,2008,884],{"class":204},[190,2010,1976],{"class":440},[190,2012,443],{"class":204},[190,2014,446],{"class":204},[190,2016,2017],{"class":449},"root",[190,2019,453],{"class":204},[190,2021,899],{"class":204},[190,2023,2024],{"class":440}," next",[190,2026,443],{"class":204},[190,2028,1965],{"class":200},[190,2030,911],{"class":204},[190,2032,2033,2035,2037,2039,2041,2044,2046,2048,2050,2052,2054],{"class":192,"line":302},[190,2034,884],{"class":204},[190,2036,1976],{"class":440},[190,2038,443],{"class":204},[190,2040,446],{"class":204},[190,2042,2043],{"class":449},"alt",[190,2045,453],{"class":204},[190,2047,899],{"class":204},[190,2049,2024],{"class":440},[190,2051,443],{"class":204},[190,2053,1965],{"class":200},[190,2055,911],{"class":204},[190,2057,2058,2060],{"class":192,"line":307},[190,2059,942],{"class":200},[190,2061,225],{"class":204},[190,2063,2064],{"class":192,"line":330},[190,2065,255],{"emptyLinePlaceholder":254},[190,2067,2068,2070,2073,2075,2077,2079,2081,2084,2086,2088,2090,2092,2094,2096,2098,2100,2102],{"class":192,"line":520},[190,2069,197],{"class":196},[190,2071,2072],{"class":200}," encodeList ",[190,2074,205],{"class":204},[190,2076,209],{"class":208},[190,2078,212],{"class":204},[190,2080,1688],{"class":215},[190,2082,2083],{"class":200},"[]",[190,2085,219],{"class":204},[190,2087,434],{"class":200},[190,2089,1695],{"class":204},[190,2091,1106],{"class":204},[190,2093,1650],{"class":440},[190,2095,443],{"class":204},[190,2097,1705],{"class":1704},[190,2099,456],{"class":204},[190,2101,459],{"class":200},[190,2103,225],{"class":204},[190,2105,2106,2109,2112,2114],{"class":192,"line":526},[190,2107,2108],{"class":208},"encodeList",[190,2110,2111],{"class":200},"(dag)",[190,2113,274],{"class":204},[190,2115,2116],{"class":277}," \u002F\u002F encodes normally — no cycle\n",[1055,2118,2119,2120,2122,2123,160,2125,2128,2129,2132,2133,160,2135,2138,2139,2142],{},"The same ",[141,2121,1650],{}," option is available on ",[141,2124,1622],{},[141,2126,2127],{},"createGetValidationErrors",". There, ",[141,2130,2131],{},"validate"," returns ",[141,2134,1929],{},[141,2136,2137],{},"getValidationErrors"," records a ",[141,2140,2141],{},"{expected: 'circular'}"," entry instead of throwing. Decoders need no guard: a serialized payload can't contain a runtime cycle. The whole guard is off by default; arm it only where you process values that might cycle.",[133,2144,2146,2147],{"id":2145},"decoders-return-dataonlyt","Decoders return ",[141,2148,2149],{},"DataOnly\u003CT>",[138,2151,2152,2153,160,2156,2159,2160,2162,2163,2166],{},"Both ",[141,2154,2155],{},"createJsonDecoder\u003CT>()",[141,2157,2158],{},"createBinaryDecoder\u003CT>()"," return ",[141,2161,2149],{},", not bare ",[141,2164,2165],{},"T",". A value rebuilt from JSON or bytes can only hold serializable data. Anything that can't ride the wire (methods, for one) was never there, so the return type leaves it out and stops you from reaching for it.",[181,2168,2170],{"className":183,"code":2169,"language":185,"meta":186,"style":186},"const decode = createJsonDecoder\u003CCart>();\n\n\u002F\u002F The decoder returns DataOnly\u003CCart>, not Cart — the method is gone from the\n\u002F\u002F type because it was never on the wire. TS now stops you from calling it.\nconst cart = decode('{\"items\":[\"TS-7\"],\"total\":42}');\n\ncart.items; \u002F\u002F string[]  ✅\ncart.total; \u002F\u002F number    ✅\n\u002F\u002F cart.checkout();      ❌ TS error — checkout isn't part of DataOnly\u003CCart>\n",[141,2171,2172,2193,2197,2202,2207,2231,2235,2250,2264],{"__ignoreMap":186},[190,2173,2174,2176,2178,2180,2182,2184,2187,2189,2191],{"class":192,"line":193},[190,2175,197],{"class":196},[190,2177,233],{"class":200},[190,2179,205],{"class":204},[190,2181,238],{"class":208},[190,2183,212],{"class":204},[190,2185,2186],{"class":215},"Cart",[190,2188,219],{"class":204},[190,2190,222],{"class":200},[190,2192,225],{"class":204},[190,2194,2195],{"class":192,"line":228},[190,2196,255],{"emptyLinePlaceholder":254},[190,2198,2199],{"class":192,"line":251},[190,2200,2201],{"class":277},"\u002F\u002F The decoder returns DataOnly\u003CCart>, not Cart — the method is gone from the\n",[190,2203,2204],{"class":192,"line":258},[190,2205,2206],{"class":277},"\u002F\u002F type because it was never on the wire. TS now stops you from calling it.\n",[190,2208,2209,2211,2214,2216,2218,2220,2222,2225,2227,2229],{"class":192,"line":281},[190,2210,197],{"class":196},[190,2212,2213],{"class":200}," cart ",[190,2215,205],{"class":204},[190,2217,291],{"class":208},[190,2219,434],{"class":200},[190,2221,453],{"class":204},[190,2223,2224],{"class":449},"{\"items\":[\"TS-7\"],\"total\":42}",[190,2226,453],{"class":204},[190,2228,459],{"class":200},[190,2230,225],{"class":204},[190,2232,2233],{"class":192,"line":302},[190,2234,255],{"emptyLinePlaceholder":254},[190,2236,2237,2240,2242,2245,2247],{"class":192,"line":307},[190,2238,2239],{"class":200},"cart",[190,2241,313],{"class":204},[190,2243,2244],{"class":200},"items",[190,2246,274],{"class":204},[190,2248,2249],{"class":277}," \u002F\u002F string[]  ✅\n",[190,2251,2252,2254,2256,2259,2261],{"class":192,"line":330},[190,2253,2239],{"class":200},[190,2255,313],{"class":204},[190,2257,2258],{"class":200},"total",[190,2260,274],{"class":204},[190,2262,2263],{"class":277}," \u002F\u002F number    ✅\n",[190,2265,2266],{"class":192,"line":520},[190,2267,2268],{"class":277},"\u002F\u002F cart.checkout();      ❌ TS error — checkout isn't part of DataOnly\u003CCart>\n",[138,2270,2271],{},"This isn't a runtime cost. It's the type telling the truth about what came back.",[133,2273,2275],{"id":2274},"one-contract-serializable-data-only","One contract: serializable data only",[138,2277,2278,2279,2282,2283,2286,2287,313],{},"Validation and both codecs operate on the ",[629,2280,2281],{},"serializable projection"," of your type, not every last TypeScript member. Functions, methods and symbol keys are silently dropped. They don't survive JSON anyway, so a ",[141,2284,2285],{},"{name: string; onClick: () => void}"," produces a validator that only checks ",[141,2288,1976],{},[138,2290,2291,2292,2295,2296,2299,2300,2303,2304,313],{},"This is on purpose, and the build tells you when it happens with a ",[141,2293,2294],{},"VL010","-family ",[629,2297,2298],{},"Warning",", not an error. (At a position that would throw at runtime, like a union member or array element, it's escalated to an ",[629,2301,2302],{},"Error"," and the build fails instead.) The reasoning is in ",[2305,2306,12],"a",{"href":2307},"\u002Fintroduction\u002Fabout-ts-runtypes#a-deliberate-contract-serializable-data",[133,2309,2311],{"id":2310},"binary-payload-size","Binary payload size",[138,2313,2314,2315,2318,2319,2322,2323,2318,2326,2329,2330,160,2333,2336,2337,2340,2341,2344,2345,2348],{},"Binary is the strategy that wins big when your types carry format constraints. The codec reserves a worst case width whenever it cannot tell a value's range, so an unconstrained ",[141,2316,2317],{},"number"," or ",[141,2320,2321],{},"bigint"," rides the wire as a fixed 8 bytes. Once the type pins the value into a known range (a fixed width like ",[141,2324,2325],{},"int8",[141,2327,2328],{},"uint16",", or a ",[141,2331,2332],{},"min",[141,2334,2335],{},"max"," bound), the encoder packs it into far fewer bytes (a ",[141,2338,2339],{},"uint8"," into 1 byte, a ",[141,2342,2343],{},"{min: 0, max: 1000}"," number into 2). The ",[2305,2346,2347],{"href":121},"serialization formats benchmark"," pairs each unconstrained value against its constrained twin, so you can read the saving off directly.",[2350,2351,2352],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}","JSON and binary codecs generated from your type, so Date, BigInt, Map and Set survive the round-trip.","md",null,{"toc":18},{"title":34,"description":2353},"_OzI6UVgHlP5C9nDHhMLKncjcYaRCSUxW4scny0huXA",[2360,2362],{"title":30,"path":31,"stem":32,"description":2361,"children":-1},"Bake constraints like email, UUID, int32 or positive straight into your types or schemas.",{"title":38,"path":39,"stem":40,"description":2363,"children":-1},"Generate valid, type-shaped fake data for tests and fixtures.",1781995977194]