[{"data":1,"prerenderedAt":517},["ShallowReactive",2],{"navigation_docs":3,"-suites-fuzzing":127,"-suites-fuzzing-surround":512},[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":92,"body":129,"description":505,"extension":506,"links":507,"meta":508,"navigation":509,"path":93,"seo":510,"stem":94,"__hash__":511},"docs\u002F6.suites\u002F5.fuzzing.md",{"type":130,"value":131,"toc":498},"minimark",[132,141,152,157,160,163,182,185,189,195,201,204,386,390,393,420,424,427,433,440,447,450,454,457,463,473,479,485,491,494],[133,134,135,136,140],"p",{},"The suites on the previous pages are hand-written: real types, real values, known answers. They're thorough, but they only try the inputs ",[137,138,139],"strong",{},"we"," thought of. Fuzzing covers the rest: the weird, the malformed, and the cases nobody would write by hand.",[133,142,143,144,147,148,151],{},"RunTypes is fuzzed on two levels at once: random ",[137,145,146],{},"values",", and random ",[137,149,150],{},"types",". Both run through the real build pipeline, and both are checked against rules that must hold for every input, never a hand-picked expected answer.",[153,154,156],"h2",{"id":155},"properties-not-examples","Properties, not examples",[133,158,159],{},"A normal test says \"validate should return true for this value.\" A fuzz oracle says something stronger: a property that has to hold no matter what the input is. When a property breaks we have found a bug, even though nobody wrote a test for that exact case.",[133,161,162],{},"The rules we check include:",[164,165,166,170,173,176,179],"ul",{},[167,168,169],"li",{},"validate always returns a boolean and never throws, for any input at all.",[167,171,172],{},"validate(x) is true exactly when getValidationErrors(x) is empty. The two can never disagree.",[167,174,175],{},"A value survives a JSON round-trip unchanged, and survives a binary round-trip unchanged.",[167,177,178],{},"The JSON wire and the binary wire decode to the same value. Two independent encoders, one answer.",[167,180,181],{},"Every serializer in a family agrees on whether a given type can be serialized at all.",[133,183,184],{},"None of these is a hand-written answer. They are laws the library promises to uphold, and the fuzzer tries thousands of random ways to break each one.",[153,186,188],{"id":187},"two-levels-of-randomness","Two levels of randomness",[133,190,191,194],{},[137,192,193],{},"Random values."," For a fixed set of types, generate a flood of conforming values, deliberately broken values, and pure junk. Check every rule against every one.",[133,196,197,200],{},[137,198,199],{},"Random types."," This is the part most libraries never attempt. We generate the types themselves: arbitrary, valid but strange TypeScript. Unions, intersections, recursive interfaces, tuples, index signatures, Map and Set, classes, and the awkward non-data members like symbols, functions, methods, and typed arrays. Each generated type is fed through the entire build pipeline, which produces a real validator and real encoders and decoders, and those are then fuzzed like any other.",[133,202,203],{},"A single run might invent a type like this, build everything for it, and confirm it all behaves:",[205,206,211],"pre",{"className":207,"code":208,"language":209,"meta":210,"style":210},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","type Account = {\n  id: bigint;\n  labels: Set\u003Cstring>;\n  status: {kind: 'active'; since: Date} | {kind: 'closed'};\n  refresh: () => void; \u002F\u002F a non-data member\n  [extra: string]: unknown; \u002F\u002F an index signature\n};\n","ts","",[212,213,214,234,250,270,329,352,381],"code",{"__ignoreMap":210},[215,216,219,223,227,231],"span",{"class":217,"line":218},"line",1,[215,220,222],{"class":221},"spNyl","type",[215,224,226],{"class":225},"sBMFI"," Account",[215,228,230],{"class":229},"sMK4o"," =",[215,232,233],{"class":229}," {\n",[215,235,237,241,244,247],{"class":217,"line":236},2,[215,238,240],{"class":239},"swJcz","  id",[215,242,243],{"class":229},":",[215,245,246],{"class":225}," bigint",[215,248,249],{"class":229},";\n",[215,251,253,256,258,261,264,267],{"class":217,"line":252},3,[215,254,255],{"class":239},"  labels",[215,257,243],{"class":229},[215,259,260],{"class":225}," Set",[215,262,263],{"class":229},"\u003C",[215,265,266],{"class":225},"string",[215,268,269],{"class":229},">;\n",[215,271,273,276,278,281,284,286,289,293,296,299,302,304,307,310,313,315,317,319,321,324,326],{"class":217,"line":272},4,[215,274,275],{"class":239},"  status",[215,277,243],{"class":229},[215,279,280],{"class":229}," {",[215,282,283],{"class":239},"kind",[215,285,243],{"class":229},[215,287,288],{"class":229}," '",[215,290,292],{"class":291},"sfazB","active",[215,294,295],{"class":229},"'",[215,297,298],{"class":229},";",[215,300,301],{"class":239}," since",[215,303,243],{"class":229},[215,305,306],{"class":225}," Date",[215,308,309],{"class":229},"}",[215,311,312],{"class":229}," |",[215,314,280],{"class":229},[215,316,283],{"class":239},[215,318,243],{"class":229},[215,320,288],{"class":229},[215,322,323],{"class":291},"closed",[215,325,295],{"class":229},[215,327,328],{"class":229},"};\n",[215,330,332,335,337,340,343,346,348],{"class":217,"line":331},5,[215,333,334],{"class":239},"  refresh",[215,336,243],{"class":229},[215,338,339],{"class":229}," ()",[215,341,342],{"class":221}," =>",[215,344,345],{"class":225}," void",[215,347,298],{"class":229},[215,349,351],{"class":350},"sHwdD"," \u002F\u002F a non-data member\n",[215,353,355,359,363,365,368,371,373,376,378],{"class":217,"line":354},6,[215,356,358],{"class":357},"sTEyZ","  [",[215,360,362],{"class":361},"sHdIc","extra",[215,364,243],{"class":229},[215,366,367],{"class":225}," string",[215,369,370],{"class":357},"]",[215,372,243],{"class":229},[215,374,375],{"class":225}," unknown",[215,377,298],{"class":229},[215,379,380],{"class":350}," \u002F\u002F an index signature\n",[215,382,384],{"class":217,"line":383},7,[215,385,328],{"class":229},[153,387,389],{"id":388},"how-a-run-is-built","How a run is built",[133,391,392],{},"Each iteration does four things, all driven from a single seed so any finding replays exactly:",[394,395,396,402,408,414],"ol",{},[167,397,398,401],{},[137,399,400],{},"Invent a type."," A recursive generator builds a random type across the widest shape space we can express.",[167,403,404,407],{},[137,405,406],{},"Compile it for real."," The type goes through the actual resolver and plugin, the same path a user's build takes. If the pipeline crashes, hangs, or emits code that will not run, that alone is a finding.",[167,409,410,413],{},[137,411,412],{},"Build a real value."," The value comes from our own mock generator, the same one users call, walking the compiled type to produce a conforming value. Routing the real mock through the real serializers tests the whole stack from end to end, not a simplified stand-in.",[167,415,416,419],{},[137,417,418],{},"Check the rules."," Run the oracles. Any broken property reports the seed that broke it.",[153,421,423],{"id":422},"why-this-finds-what-others-miss","Why this finds what others miss",[133,425,426],{},"Three choices do the heavy lifting.",[133,428,429,430,432],{},"We fuzz the ",[137,431,150],{},", not only the values. A library that only fuzzes values can never discover that a particular shape of type compiles to a broken function. We generate the shapes.",[133,434,435,436,439],{},"We feed values from the ",[137,437,438],{},"real mock generator",", not a hand-tuned helper. That means the mock, the validator, and both serializers are all exercised together. A disagreement anywhere shows up.",[133,441,442,443,446],{},"We check ",[137,444,445],{},"metamorphic properties"," (round-trip stability, cross-wire agreement, family agreement) instead of expected answers. These catch bugs nobody would write a test for, because nobody imagined the input.",[133,448,449],{},"There is one more thing this style is uniquely good at. RunTypes serializes the data-only projection of a type: a method, a symbol, or a typed array carries no JSON-shaped value, so it is dropped where that is safe and refused where it is not. The fuzzer mints values that deliberately contain those non-data members, then confirms each one is handled the right way: dropped from a property, kept across a round-trip where the surrounding data survives, or rejected outright when a whole value could never be represented. That contract is far too large to cover by hand. The fuzzer covers it automatically.",[153,451,453],{"id":452},"the-bugs-it-caught","The bugs it caught",[133,455,456],{},"This is the part that pays for itself.",[133,458,459,462],{},[137,460,461],{},"A binary buffer overflow."," The very first type-level run found that the binary encoder could overrun its output buffer on a perfectly valid value, but only after a run of smaller values had sized the buffer a certain way. No hand-written test would have lined up that sequence. Found, fixed, and pinned with a regression test.",[133,464,465,468,469,472],{},[137,466,467],{},"A serializer that confused two kinds of key."," Routing real generated values through the binary serializer surfaced an object that mixes an index signature with named properties, much like the ",[212,470,471],{},"Account"," type above. On that shape the binary encoder applied the index-signature rule to the named properties as well, and fell over, while JSON encoded the same value correctly. Two wires, one value, two different outcomes: the cross-wire rule flagged it on the spot. It is exactly the corner no example test reaches, a named property and a catch-all signature living on the same object, carrying different types.",[133,474,475,478],{},[137,476,477],{},"A union branch that should have serialized."," A union where one branch is an object holding a single non-data property, say a lone symbol, was rejected as a whole by the serializers. The very same object on its own would quietly drop that property and serialize the rest. Two paths through the code, two answers for one shape, and the fuzzer found the gap.",[133,480,481,484],{},[137,482,483],{},"Two features disagreeing about callable interfaces."," An interface you can call like a function is treated as a function by the validator and as a plain object by the serializers. No single value is valid for both at once, so the fuzzer could never build one that round-trips, and that contradiction is itself the report.",[133,486,487,490],{},[137,488,489],{},"An error that should have been a warning."," The build flagged a hard error on a value that serializes perfectly at runtime, because the part of the type it objected to was going to be dropped anyway. A hard error is supposed to mean \"this will throw,\" so a clean round-trip sitting next to one is a real signal. The fuzzer noticed the two disagreeing.",[133,492,493],{},"Every finding arrives with a seed. Replay the seed, watch it fail, fix it, then keep the seed as a permanent test. That loop is why a feature can change and we still trust that thousands of strange types and values keep behaving.",[495,496,497],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .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 pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}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 .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);}",{"title":210,"searchDepth":236,"depth":236,"links":499},[500,501,502,503,504],{"id":155,"depth":236,"text":156},{"id":187,"depth":236,"text":188},{"id":388,"depth":236,"text":389},{"id":422,"depth":236,"text":423},{"id":452,"depth":236,"text":453},"Generating random types and values to catch bugs that hand-written tests never reach.","md",null,{"toc":509},true,{"title":92,"description":505},"951glzPYgtwMfvhlVWQnh5ejVmAAXrfEqweUaAJ5K2o",[513,515],{"title":88,"path":89,"stem":90,"description":514,"children":-1},"Serializing format-typed fields through JSON and binary.",{"title":42,"path":98,"stem":103,"description":516,"children":-1},"How fast each library runs validate, the fast boolean check that a value matches its type.",1781995977193]