[{"data":1,"prerenderedAt":1475},["ShallowReactive",2],{"navigation_docs":3,"-guide-markers-and-reflection":127,"-guide-markers-and-reflection-surround":1470},[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":46,"body":129,"description":1464,"extension":1465,"links":1466,"meta":1467,"navigation":201,"path":47,"seo":1468,"stem":48,"__hash__":1469},"docs\u002F2.guide\u002F6.markers-and-reflection.md",{"type":130,"value":131},"minimark",[132,137,145,395,403,414,418,429,436,686,689,698,702,717,977,992,996,999,1297,1300,1304,1308,1314,1457,1460],[133,134,136],"h2",{"id":135},"a-stable-id-for-any-type","A stable id for any type",[138,139,140,144],"p",{},[141,142,143],"code",{},"getRunTypeId"," hands you a short, stable id for any type. Bring the type yourself, or let it infer the type from a value you already have. Either way you get the same id back.",[146,147,152],"pre",{"className":148,"code":149,"language":150,"meta":151,"style":151},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F packages\u002Fexamples\u002Fsrc\u002Fguide\u002Fmarkers-reflection.ts\nimport {getRunTypeId} from 'ts-runtypes';\n\n\u002F\u002F Static form — you bring the type, you get its id. No value needed.\nconst stringId = getRunTypeId\u003Cstring>(); \u002F\u002F e.g. \"Sq3kZ1\"\nconst userId = getRunTypeId\u003C{id: number; name: string}>();\n\n\u002F\u002F Reflection form — T is inferred from a value. The value is only read for\n\u002F\u002F its type; at runtime it's ignored, so nothing leaks into the output.\nconst order = {id: 1, total: 42};\nconst orderId = getRunTypeId(order);\n\n\u002F\u002F Same shape in, same id out — getRunTypeId\u003C{id: number}>() and a value of\n\u002F\u002F that shape resolve to the exact same string.\nexport {stringId, userId, orderId};\n","ts","",[141,153,154,163,196,203,209,245,287,292,298,304,338,355,360,366,372],{"__ignoreMap":151},[155,156,159],"span",{"class":157,"line":158},"line",1,[155,160,162],{"class":161},"sHwdD","\u002F\u002F packages\u002Fexamples\u002Fsrc\u002Fguide\u002Fmarkers-reflection.ts\n",[155,164,166,170,174,177,180,183,186,190,193],{"class":157,"line":165},2,[155,167,169],{"class":168},"s7zQu","import",[155,171,173],{"class":172},"sMK4o"," {",[155,175,143],{"class":176},"sTEyZ",[155,178,179],{"class":172},"}",[155,181,182],{"class":168}," from",[155,184,185],{"class":172}," '",[155,187,189],{"class":188},"sfazB","ts-runtypes",[155,191,192],{"class":172},"'",[155,194,195],{"class":172},";\n",[155,197,199],{"class":157,"line":198},3,[155,200,202],{"emptyLinePlaceholder":201},true,"\n",[155,204,206],{"class":157,"line":205},4,[155,207,208],{"class":161},"\u002F\u002F Static form — you bring the type, you get its id. No value needed.\n",[155,210,212,216,219,222,226,229,233,236,239,242],{"class":157,"line":211},5,[155,213,215],{"class":214},"spNyl","const",[155,217,218],{"class":176}," stringId ",[155,220,221],{"class":172},"=",[155,223,225],{"class":224},"s2Zo4"," getRunTypeId",[155,227,228],{"class":172},"\u003C",[155,230,232],{"class":231},"sBMFI","string",[155,234,235],{"class":172},">",[155,237,238],{"class":176},"()",[155,240,241],{"class":172},";",[155,243,244],{"class":161}," \u002F\u002F e.g. \"Sq3kZ1\"\n",[155,246,248,250,253,255,257,260,264,267,270,272,275,277,280,283,285],{"class":157,"line":247},6,[155,249,215],{"class":214},[155,251,252],{"class":176}," userId ",[155,254,221],{"class":172},[155,256,225],{"class":224},[155,258,259],{"class":172},"\u003C{",[155,261,263],{"class":262},"swJcz","id",[155,265,266],{"class":172},":",[155,268,269],{"class":231}," number",[155,271,241],{"class":172},[155,273,274],{"class":262}," name",[155,276,266],{"class":172},[155,278,279],{"class":231}," string",[155,281,282],{"class":172},"}>",[155,284,238],{"class":176},[155,286,195],{"class":172},[155,288,290],{"class":157,"line":289},7,[155,291,202],{"emptyLinePlaceholder":201},[155,293,295],{"class":157,"line":294},8,[155,296,297],{"class":161},"\u002F\u002F Reflection form — T is inferred from a value. The value is only read for\n",[155,299,301],{"class":157,"line":300},9,[155,302,303],{"class":161},"\u002F\u002F its type; at runtime it's ignored, so nothing leaks into the output.\n",[155,305,307,309,312,314,316,318,320,324,327,330,332,335],{"class":157,"line":306},10,[155,308,215],{"class":214},[155,310,311],{"class":176}," order ",[155,313,221],{"class":172},[155,315,173],{"class":172},[155,317,263],{"class":262},[155,319,266],{"class":172},[155,321,323],{"class":322},"sbssI"," 1",[155,325,326],{"class":172},",",[155,328,329],{"class":262}," total",[155,331,266],{"class":172},[155,333,334],{"class":322}," 42",[155,336,337],{"class":172},"};\n",[155,339,341,343,346,348,350,353],{"class":157,"line":340},11,[155,342,215],{"class":214},[155,344,345],{"class":176}," orderId ",[155,347,221],{"class":172},[155,349,225],{"class":224},[155,351,352],{"class":176},"(order)",[155,354,195],{"class":172},[155,356,358],{"class":157,"line":357},12,[155,359,202],{"emptyLinePlaceholder":201},[155,361,363],{"class":157,"line":362},13,[155,364,365],{"class":161},"\u002F\u002F Same shape in, same id out — getRunTypeId\u003C{id: number}>() and a value of\n",[155,367,369],{"class":157,"line":368},14,[155,370,371],{"class":161},"\u002F\u002F that shape resolve to the exact same string.\n",[155,373,375,378,380,383,385,388,390,393],{"class":157,"line":374},15,[155,376,377],{"class":168},"export",[155,379,173],{"class":172},[155,381,382],{"class":176},"stringId",[155,384,326],{"class":172},[155,386,387],{"class":176}," userId",[155,389,326],{"class":172},[155,391,392],{"class":176}," orderId",[155,394,337],{"class":172},[138,396,397,398,402],{},"The id is a fingerprint of the type's ",[399,400,401],"em",{},"shape",", so two types that look the same share one id. Use it as a cache key, a registry key, a discriminator, or whatever you need.",[404,405,406,407,409,410],"note",{},"These run at build time. With the Vite plugin off there's no id to inject, so ",[141,408,143],{}," throws rather than guess. ",[411,412,413],"a",{"href":7},"The design behind it.",[133,415,417],{"id":416},"injectruntypeid-the-one-youll-type","InjectRunTypeId, the one you'll type",[138,419,420,421,424,425],{},"Every ",[141,422,423],{},"createX"," factory works because of one trick: a trailing parameter the build fills in with the type's id at each call site. The good news is that ",[426,427,428],"strong",{},"you can use the same trick yourself.",[138,430,431,432,435],{},"Add a trailing ",[141,433,434],{},"id?: InjectRunTypeId\u003CT>"," to a generic function and it opts in. The build injects the id at every call site, so you never pass it by hand.",[146,437,439],{"className":148,"code":438,"language":150,"meta":151,"style":151},"\u002F\u002F packages\u002Fexamples\u002Fsrc\u002Fguide\u002Fmarkers-wrap-helper.ts\nimport {getRTUtils, type InjectRunTypeId} from 'ts-runtypes';\n\n\u002F\u002F Wrap ts-runtypes into your OWN helper. Declare a trailing\n\u002F\u002F `id?: InjectRunTypeId\u003CT>` parameter and the build fills it in at every\n\u002F\u002F call site — you never pass the id yourself.\nfunction describe\u003CT>(id?: InjectRunTypeId\u003CT>): string {\n  \u002F\u002F At runtime `id` is just the resolved hash string. Look the type up in\n  \u002F\u002F the registry and do whatever your helper needs.\n  const runType = getRTUtils().getRunType(id!);\n  return runType ? `type #${id}` : 'unknown type';\n}\n\n\u002F\u002F Call it like any generic function — no id argument in sight.\ndescribe\u003C{id: number; name: string}>();\ndescribe\u003Cstring[]>();\n\nexport {describe};\n",[141,440,441,446,475,479,484,489,494,530,535,540,575,611,616,620,625,652,670,675],{"__ignoreMap":151},[155,442,443],{"class":157,"line":158},[155,444,445],{"class":161},"\u002F\u002F packages\u002Fexamples\u002Fsrc\u002Fguide\u002Fmarkers-wrap-helper.ts\n",[155,447,448,450,452,455,457,460,463,465,467,469,471,473],{"class":157,"line":165},[155,449,169],{"class":168},[155,451,173],{"class":172},[155,453,454],{"class":176},"getRTUtils",[155,456,326],{"class":172},[155,458,459],{"class":168}," type",[155,461,462],{"class":176}," InjectRunTypeId",[155,464,179],{"class":172},[155,466,182],{"class":168},[155,468,185],{"class":172},[155,470,189],{"class":188},[155,472,192],{"class":172},[155,474,195],{"class":172},[155,476,477],{"class":157,"line":198},[155,478,202],{"emptyLinePlaceholder":201},[155,480,481],{"class":157,"line":205},[155,482,483],{"class":161},"\u002F\u002F Wrap ts-runtypes into your OWN helper. Declare a trailing\n",[155,485,486],{"class":157,"line":211},[155,487,488],{"class":161},"\u002F\u002F `id?: InjectRunTypeId\u003CT>` parameter and the build fills it in at every\n",[155,490,491],{"class":157,"line":247},[155,492,493],{"class":161},"\u002F\u002F call site — you never pass the id yourself.\n",[155,495,496,499,502,504,507,510,513,516,518,520,522,525,527],{"class":157,"line":289},[155,497,498],{"class":214},"function",[155,500,501],{"class":224}," describe",[155,503,228],{"class":172},[155,505,506],{"class":231},"T",[155,508,509],{"class":172},">(",[155,511,263],{"class":512},"sHdIc",[155,514,515],{"class":172},"?:",[155,517,462],{"class":231},[155,519,228],{"class":172},[155,521,506],{"class":231},[155,523,524],{"class":172},">):",[155,526,279],{"class":231},[155,528,529],{"class":172}," {\n",[155,531,532],{"class":157,"line":294},[155,533,534],{"class":161},"  \u002F\u002F At runtime `id` is just the resolved hash string. Look the type up in\n",[155,536,537],{"class":157,"line":300},[155,538,539],{"class":161},"  \u002F\u002F the registry and do whatever your helper needs.\n",[155,541,542,545,548,551,554,556,559,562,565,567,570,573],{"class":157,"line":306},[155,543,544],{"class":214},"  const",[155,546,547],{"class":176}," runType",[155,549,550],{"class":172}," =",[155,552,553],{"class":224}," getRTUtils",[155,555,238],{"class":262},[155,557,558],{"class":172},".",[155,560,561],{"class":224},"getRunType",[155,563,564],{"class":262},"(",[155,566,263],{"class":176},[155,568,569],{"class":172},"!",[155,571,572],{"class":262},")",[155,574,195],{"class":172},[155,576,577,580,582,585,588,591,594,596,599,602,604,607,609],{"class":157,"line":340},[155,578,579],{"class":168},"  return",[155,581,547],{"class":176},[155,583,584],{"class":172}," ?",[155,586,587],{"class":172}," `",[155,589,590],{"class":188},"type #",[155,592,593],{"class":172},"${",[155,595,263],{"class":176},[155,597,598],{"class":172},"}`",[155,600,601],{"class":172}," :",[155,603,185],{"class":172},[155,605,606],{"class":188},"unknown type",[155,608,192],{"class":172},[155,610,195],{"class":172},[155,612,613],{"class":157,"line":357},[155,614,615],{"class":172},"}\n",[155,617,618],{"class":157,"line":362},[155,619,202],{"emptyLinePlaceholder":201},[155,621,622],{"class":157,"line":368},[155,623,624],{"class":161},"\u002F\u002F Call it like any generic function — no id argument in sight.\n",[155,626,627,630,632,634,636,638,640,642,644,646,648,650],{"class":157,"line":374},[155,628,629],{"class":224},"describe",[155,631,259],{"class":172},[155,633,263],{"class":262},[155,635,266],{"class":172},[155,637,269],{"class":231},[155,639,241],{"class":172},[155,641,274],{"class":262},[155,643,266],{"class":172},[155,645,279],{"class":231},[155,647,282],{"class":172},[155,649,238],{"class":176},[155,651,195],{"class":172},[155,653,655,657,659,661,664,666,668],{"class":157,"line":654},16,[155,656,629],{"class":224},[155,658,228],{"class":172},[155,660,232],{"class":231},[155,662,663],{"class":176},"[]",[155,665,235],{"class":172},[155,667,238],{"class":176},[155,669,195],{"class":172},[155,671,673],{"class":157,"line":672},17,[155,674,202],{"emptyLinePlaceholder":201},[155,676,678,680,682,684],{"class":157,"line":677},18,[155,679,377],{"class":168},[155,681,173],{"class":172},[155,683,629],{"class":176},[155,685,337],{"class":172},[138,687,688],{},"The call looks like any ordinary generic call, but inside, the injected id is just the type's hash, ready to look up or branch on.",[404,690,691,692,694,695,697],{},"The marker only fires where ",[141,693,506],{}," is concrete, at a real call site, not inside a generic body. To pass it through your own generic function, declare ",[141,696,434],{}," and let the build fill it at each call site (exactly what the wrapper examples below do).",[133,699,701],{"id":700},"arguments-read-at-compile-time","Arguments read at compile time",[138,703,704,705,708,709,712,713,716],{},"Some factory arguments aren't ordinary runtime values, such as the ",[141,706,707],{},"ValidateOptions"," bag or the JSON encoder ",[141,710,711],{},"strategy",". The build reads them to choose the exact specialized function it emits, so each one has to be a ",[426,714,715],{},"literal written at the call site",". A variable won't do: the build can't see its value.",[146,718,720],{"className":148,"code":719,"language":150,"meta":151,"style":151},"\u002F\u002F packages\u002Fexamples\u002Fsrc\u002Fguide\u002Fmarkers-comptime.ts\nimport {createValidate, createJsonEncoder} from 'ts-runtypes';\n\ntype Flag = {kind: 'on' | 'off'};\n\n\u002F\u002F These options are read by the BUILD, so they must be a literal written right\n\u002F\u002F at the call site — the build picks the specialized function from what it sees.\nconst isFlag = createValidate\u003CFlag>({noLiterals: true});\nconst encode = createJsonEncoder\u003CFlag>({strategy: 'direct'});\n\n\u002F\u002F A computed value is NOT a literal, so the build can't read it — this line\n\u002F\u002F fails compilation with a CTA diagnostic.\nconst looseAtNight = new Date().getHours() \u003C 6;\ncreateValidate\u003CFlag>({noLiterals: looseAtNight});\n\nexport {isFlag, encode};\n",[141,721,722,727,753,757,793,797,802,807,846,884,888,893,898,930,957,961],{"__ignoreMap":151},[155,723,724],{"class":157,"line":158},[155,725,726],{"class":161},"\u002F\u002F packages\u002Fexamples\u002Fsrc\u002Fguide\u002Fmarkers-comptime.ts\n",[155,728,729,731,733,736,738,741,743,745,747,749,751],{"class":157,"line":165},[155,730,169],{"class":168},[155,732,173],{"class":172},[155,734,735],{"class":176},"createValidate",[155,737,326],{"class":172},[155,739,740],{"class":176}," createJsonEncoder",[155,742,179],{"class":172},[155,744,182],{"class":168},[155,746,185],{"class":172},[155,748,189],{"class":188},[155,750,192],{"class":172},[155,752,195],{"class":172},[155,754,755],{"class":157,"line":198},[155,756,202],{"emptyLinePlaceholder":201},[155,758,759,762,765,767,769,772,774,776,779,781,784,786,789,791],{"class":157,"line":205},[155,760,761],{"class":214},"type",[155,763,764],{"class":231}," Flag",[155,766,550],{"class":172},[155,768,173],{"class":172},[155,770,771],{"class":262},"kind",[155,773,266],{"class":172},[155,775,185],{"class":172},[155,777,778],{"class":188},"on",[155,780,192],{"class":172},[155,782,783],{"class":172}," |",[155,785,185],{"class":172},[155,787,788],{"class":188},"off",[155,790,192],{"class":172},[155,792,337],{"class":172},[155,794,795],{"class":157,"line":211},[155,796,202],{"emptyLinePlaceholder":201},[155,798,799],{"class":157,"line":247},[155,800,801],{"class":161},"\u002F\u002F These options are read by the BUILD, so they must be a literal written right\n",[155,803,804],{"class":157,"line":289},[155,805,806],{"class":161},"\u002F\u002F at the call site — the build picks the specialized function from what it sees.\n",[155,808,809,811,814,816,819,821,824,826,828,831,834,836,840,842,844],{"class":157,"line":294},[155,810,215],{"class":214},[155,812,813],{"class":176}," isFlag ",[155,815,221],{"class":172},[155,817,818],{"class":224}," createValidate",[155,820,228],{"class":172},[155,822,823],{"class":231},"Flag",[155,825,235],{"class":172},[155,827,564],{"class":176},[155,829,830],{"class":172},"{",[155,832,833],{"class":262},"noLiterals",[155,835,266],{"class":172},[155,837,839],{"class":838},"sfNiH"," true",[155,841,179],{"class":172},[155,843,572],{"class":176},[155,845,195],{"class":172},[155,847,848,850,853,855,857,859,861,863,865,867,869,871,873,876,878,880,882],{"class":157,"line":300},[155,849,215],{"class":214},[155,851,852],{"class":176}," encode ",[155,854,221],{"class":172},[155,856,740],{"class":224},[155,858,228],{"class":172},[155,860,823],{"class":231},[155,862,235],{"class":172},[155,864,564],{"class":176},[155,866,830],{"class":172},[155,868,711],{"class":262},[155,870,266],{"class":172},[155,872,185],{"class":172},[155,874,875],{"class":188},"direct",[155,877,192],{"class":172},[155,879,179],{"class":172},[155,881,572],{"class":176},[155,883,195],{"class":172},[155,885,886],{"class":157,"line":306},[155,887,202],{"emptyLinePlaceholder":201},[155,889,890],{"class":157,"line":340},[155,891,892],{"class":161},"\u002F\u002F A computed value is NOT a literal, so the build can't read it — this line\n",[155,894,895],{"class":157,"line":357},[155,896,897],{"class":161},"\u002F\u002F fails compilation with a CTA diagnostic.\n",[155,899,900,902,905,907,910,913,915,917,920,923,925,928],{"class":157,"line":362},[155,901,215],{"class":214},[155,903,904],{"class":176}," looseAtNight ",[155,906,221],{"class":172},[155,908,909],{"class":172}," new",[155,911,912],{"class":224}," Date",[155,914,238],{"class":176},[155,916,558],{"class":172},[155,918,919],{"class":224},"getHours",[155,921,922],{"class":176},"() ",[155,924,228],{"class":172},[155,926,927],{"class":322}," 6",[155,929,195],{"class":172},[155,931,932,934,936,938,940,942,944,946,948,951,953,955],{"class":157,"line":368},[155,933,735],{"class":224},[155,935,228],{"class":172},[155,937,823],{"class":231},[155,939,235],{"class":172},[155,941,564],{"class":176},[155,943,830],{"class":172},[155,945,833],{"class":262},[155,947,266],{"class":172},[155,949,950],{"class":176}," looseAtNight",[155,952,179],{"class":172},[155,954,572],{"class":176},[155,956,195],{"class":172},[155,958,959],{"class":157,"line":374},[155,960,202],{"emptyLinePlaceholder":201},[155,962,963,965,967,970,972,975],{"class":157,"line":654},[155,964,377],{"class":168},[155,966,173],{"class":172},[155,968,969],{"class":176},"isFlag",[155,971,326],{"class":172},[155,973,974],{"class":176}," encode",[155,976,337],{"class":172},[138,978,979,980,983,984,987,988,991],{},"This rule is a marker, too. ",[141,981,982],{},"CompTimeArgs\u003CT>"," brands a parameter as \"must be a literal here\", and ",[141,985,986],{},"CompTimeFnArgs\u003CT>"," does the same for the literal that ",[399,989,990],{},"selects"," a variant (like the strategy above). The factories already declare them. You just pass a literal, and the build rejects anything else at compile time.",[133,993,995],{"id":994},"wrapping-your-own-helpers","Wrapping your own helpers",[138,997,998],{},"The real payoff is composing the generated functions into higher-level helpers, say one call that parses JSON and validates it against your type in a single step.",[146,1000,1002],{"className":148,"code":1001,"language":150,"meta":151,"style":151},"\u002F\u002F packages\u002Fexamples\u002Fsrc\u002Fguide\u002Fmarkers-wrap-parse.ts\nimport {createValidate, type InjectRunTypeId} from 'ts-runtypes';\n\n\u002F\u002F A realistic wrapper: parse JSON and validate it against T in one call.\n\u002F\u002F The trailing `id?: InjectRunTypeId\u003CT>` opts the helper into the toolchain.\nfunction parseChecked\u003CT>(raw: string, id?: InjectRunTypeId\u003CT>): T {\n  const data = JSON.parse(raw) as T;\n  \u002F\u002F Build a validator for T (createValidate is itself marker-driven).\n  const isValid = createValidate\u003CT>();\n  if (!isValid(data)) throw new Error(`bad payload for type #${id}`);\n  return data;\n}\n\ntype User = {id: number; name: string};\n\n\u002F\u002F One call site, fully typed. The build injects User's id behind the scenes.\nconst user = parseChecked\u003CUser>('{\"id\":1,\"name\":\"Ada\"}');\n\nexport {parseChecked, user};\n",[141,1003,1004,1009,1035,1039,1044,1049,1089,1120,1125,1146,1193,1201,1205,1209,1236,1240,1245,1276,1280],{"__ignoreMap":151},[155,1005,1006],{"class":157,"line":158},[155,1007,1008],{"class":161},"\u002F\u002F packages\u002Fexamples\u002Fsrc\u002Fguide\u002Fmarkers-wrap-parse.ts\n",[155,1010,1011,1013,1015,1017,1019,1021,1023,1025,1027,1029,1031,1033],{"class":157,"line":165},[155,1012,169],{"class":168},[155,1014,173],{"class":172},[155,1016,735],{"class":176},[155,1018,326],{"class":172},[155,1020,459],{"class":168},[155,1022,462],{"class":176},[155,1024,179],{"class":172},[155,1026,182],{"class":168},[155,1028,185],{"class":172},[155,1030,189],{"class":188},[155,1032,192],{"class":172},[155,1034,195],{"class":172},[155,1036,1037],{"class":157,"line":198},[155,1038,202],{"emptyLinePlaceholder":201},[155,1040,1041],{"class":157,"line":205},[155,1042,1043],{"class":161},"\u002F\u002F A realistic wrapper: parse JSON and validate it against T in one call.\n",[155,1045,1046],{"class":157,"line":211},[155,1047,1048],{"class":161},"\u002F\u002F The trailing `id?: InjectRunTypeId\u003CT>` opts the helper into the toolchain.\n",[155,1050,1051,1053,1056,1058,1060,1062,1065,1067,1069,1071,1074,1076,1078,1080,1082,1084,1087],{"class":157,"line":247},[155,1052,498],{"class":214},[155,1054,1055],{"class":224}," parseChecked",[155,1057,228],{"class":172},[155,1059,506],{"class":231},[155,1061,509],{"class":172},[155,1063,1064],{"class":512},"raw",[155,1066,266],{"class":172},[155,1068,279],{"class":231},[155,1070,326],{"class":172},[155,1072,1073],{"class":512}," id",[155,1075,515],{"class":172},[155,1077,462],{"class":231},[155,1079,228],{"class":172},[155,1081,506],{"class":231},[155,1083,524],{"class":172},[155,1085,1086],{"class":231}," T",[155,1088,529],{"class":172},[155,1090,1091,1093,1096,1098,1101,1103,1106,1108,1110,1113,1116,1118],{"class":157,"line":289},[155,1092,544],{"class":214},[155,1094,1095],{"class":176}," data",[155,1097,550],{"class":172},[155,1099,1100],{"class":176}," JSON",[155,1102,558],{"class":172},[155,1104,1105],{"class":224},"parse",[155,1107,564],{"class":262},[155,1109,1064],{"class":176},[155,1111,1112],{"class":262},") ",[155,1114,1115],{"class":168},"as",[155,1117,1086],{"class":231},[155,1119,195],{"class":172},[155,1121,1122],{"class":157,"line":294},[155,1123,1124],{"class":161},"  \u002F\u002F Build a validator for T (createValidate is itself marker-driven).\n",[155,1126,1127,1129,1132,1134,1136,1138,1140,1142,1144],{"class":157,"line":300},[155,1128,544],{"class":214},[155,1130,1131],{"class":176}," isValid",[155,1133,550],{"class":172},[155,1135,818],{"class":224},[155,1137,228],{"class":172},[155,1139,506],{"class":231},[155,1141,235],{"class":172},[155,1143,238],{"class":262},[155,1145,195],{"class":172},[155,1147,1148,1151,1154,1156,1159,1161,1164,1167,1170,1172,1175,1177,1180,1183,1185,1187,1189,1191],{"class":157,"line":306},[155,1149,1150],{"class":168},"  if",[155,1152,1153],{"class":262}," (",[155,1155,569],{"class":172},[155,1157,1158],{"class":224},"isValid",[155,1160,564],{"class":262},[155,1162,1163],{"class":176},"data",[155,1165,1166],{"class":262},")) ",[155,1168,1169],{"class":168},"throw",[155,1171,909],{"class":172},[155,1173,1174],{"class":224}," Error",[155,1176,564],{"class":262},[155,1178,1179],{"class":172},"`",[155,1181,1182],{"class":188},"bad payload for type #",[155,1184,593],{"class":172},[155,1186,263],{"class":176},[155,1188,598],{"class":172},[155,1190,572],{"class":262},[155,1192,195],{"class":172},[155,1194,1195,1197,1199],{"class":157,"line":340},[155,1196,579],{"class":168},[155,1198,1095],{"class":176},[155,1200,195],{"class":172},[155,1202,1203],{"class":157,"line":357},[155,1204,615],{"class":172},[155,1206,1207],{"class":157,"line":362},[155,1208,202],{"emptyLinePlaceholder":201},[155,1210,1211,1213,1216,1218,1220,1222,1224,1226,1228,1230,1232,1234],{"class":157,"line":368},[155,1212,761],{"class":214},[155,1214,1215],{"class":231}," User",[155,1217,550],{"class":172},[155,1219,173],{"class":172},[155,1221,263],{"class":262},[155,1223,266],{"class":172},[155,1225,269],{"class":231},[155,1227,241],{"class":172},[155,1229,274],{"class":262},[155,1231,266],{"class":172},[155,1233,279],{"class":231},[155,1235,337],{"class":172},[155,1237,1238],{"class":157,"line":374},[155,1239,202],{"emptyLinePlaceholder":201},[155,1241,1242],{"class":157,"line":654},[155,1243,1244],{"class":161},"\u002F\u002F One call site, fully typed. The build injects User's id behind the scenes.\n",[155,1246,1247,1249,1252,1254,1256,1258,1261,1263,1265,1267,1270,1272,1274],{"class":157,"line":672},[155,1248,215],{"class":214},[155,1250,1251],{"class":176}," user ",[155,1253,221],{"class":172},[155,1255,1055],{"class":224},[155,1257,228],{"class":172},[155,1259,1260],{"class":231},"User",[155,1262,235],{"class":172},[155,1264,564],{"class":176},[155,1266,192],{"class":172},[155,1268,1269],{"class":188},"{\"id\":1,\"name\":\"Ada\"}",[155,1271,192],{"class":172},[155,1273,572],{"class":176},[155,1275,195],{"class":172},[155,1277,1278],{"class":157,"line":677},[155,1279,202],{"emptyLinePlaceholder":201},[155,1281,1283,1285,1287,1290,1292,1295],{"class":157,"line":1282},19,[155,1284,377],{"class":168},[155,1286,173],{"class":172},[155,1288,1289],{"class":176},"parseChecked",[155,1291,326],{"class":172},[155,1293,1294],{"class":176}," user",[155,1296,337],{"class":172},[138,1298,1299],{},"One call site, fully typed, and the build wires the type's id through behind the scenes. Your callers never see a marker.",[1301,1302,1303],"tip",{},"The marker is the public extension point. Whenever you wonder \"can RunTypes do X?\", the answer is often \"wrap it yourself\". It's exactly how the built-in factories are built.",[133,1305,1307],{"id":1306},"all-special-markers","All Special Markers",[138,1309,1310,1311,1313],{},"You almost certainly won't type these (the ",[141,1312,423],{}," factories use them for you), but here's the cast, so nothing's a mystery.",[1315,1316,1320,1363,1393,1426],"card-group",{"className":1317},[1318,1319],"sm:grid-cols-2","rt-markers",[1321,1322,1324,1350],"card",{"title":1323},"Factory injection",[146,1325,1327],{"className":148,"code":1326,"language":150,"meta":151,"style":151},"id?: InjectTypeFnArgs\u003CT, Fn>\n",[141,1328,1329],{"__ignoreMap":151},[155,1330,1331,1333,1335,1338,1340,1342,1344,1347],{"class":157,"line":158},[155,1332,263],{"class":176},[155,1334,515],{"class":172},[155,1336,1337],{"class":176}," InjectTypeFnArgs",[155,1339,228],{"class":172},[155,1341,506],{"class":176},[155,1343,326],{"class":172},[155,1345,1346],{"class":176}," Fn",[155,1348,1349],{"class":172},">\n",[138,1351,1352,1355,1356,1359,1360,1362],{},[141,1353,1354],{},"InjectRunTypeId","'s cousin for the factories. It injects a ",[141,1357,1358],{},"[typeId, fnId]"," pair so the build emits only the function you actually asked for. Every ",[141,1361,423],{}," already declares it; you don't.",[1321,1364,1366,1387],{"title":1365},"Compile-time literals",[146,1367,1369],{"className":148,"code":1368,"language":150,"meta":151,"style":151},"options: CompTimeArgs\u003CT>\n",[141,1370,1371],{"__ignoreMap":151},[155,1372,1373,1376,1378,1381,1383,1385],{"class":157,"line":158},[155,1374,1375],{"class":231},"options",[155,1377,266],{"class":172},[155,1379,1380],{"class":176}," CompTimeArgs",[155,1382,228],{"class":172},[155,1384,506],{"class":176},[155,1386,1349],{"class":172},[138,1388,1389,1390,1392],{},"Brands a parameter as \"must be a literal at the call site\" (or a ",[141,1391,215],{}," of literals). It's how options bags get read at build time. Static check only.",[1321,1394,1396,1416],{"title":1395},"Variant selection",[146,1397,1399],{"className":148,"code":1398,"language":150,"meta":151,"style":151},"options: CompTimeFnArgs\u003CT>\n",[141,1400,1401],{"__ignoreMap":151},[155,1402,1403,1405,1407,1410,1412,1414],{"class":157,"line":158},[155,1404,1375],{"class":231},[155,1406,266],{"class":172},[155,1408,1409],{"class":176}," CompTimeFnArgs",[155,1411,228],{"class":172},[155,1413,506],{"class":176},[155,1415,1349],{"class":172},[138,1417,1418,1419,1422,1423,1425],{},"Like ",[141,1420,1421],{},"CompTimeArgs",", but the literal also ",[399,1424,990],{}," which variant of a factory you get, such as the JSON encoder strategy. Static check only.",[1321,1427,1429,1451],{"title":1428},"Pure inline functions",[146,1430,1432],{"className":148,"code":1431,"language":150,"meta":151,"style":151},"fn: PureFunction\u003CF>\n",[141,1433,1434],{"__ignoreMap":151},[155,1435,1436,1439,1441,1444,1446,1449],{"class":157,"line":158},[155,1437,1438],{"class":231},"fn",[155,1440,266],{"class":172},[155,1442,1443],{"class":176}," PureFunction",[155,1445,228],{"class":172},[155,1447,1448],{"class":176},"F",[155,1450,1349],{"class":172},[138,1452,1453,1454,558],{},"Brands a function argument as \"inline definition that passes the purity rules\". Used for ",[411,1455,1456],{"href":51},"pure functions",[138,1458,1459],{},"That's the whole family. One you'll type, and four that quietly do their job.",[1461,1462,1463],"style",{},"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 .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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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 .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 .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}","The one marker you'll actually type, for wrapping your own helpers.","md",null,{"toc":18},{"title":46,"description":1464},"fYogkgSp-hoRXtD6X9pCrUa7D4qWp4cxGP9S2RrHg84",[1471,1473],{"title":42,"path":43,"stem":44,"description":1472,"children":-1},"Type guards and error reports generated from your type at build time.",{"title":50,"path":51,"stem":52,"description":1474,"children":-1},"Extend RunTypes with pure inline helpers and your own formats and mock generators.",1781995977193]