[{"data":1,"prerenderedAt":1667},["ShallowReactive",2],{"content-\u002Fdocs\u002Fschemas\u002Fstorage-shape":3},{"id":4,"title":5,"body":6,"description":1646,"extension":1647,"meta":1648,"metaRows":1649,"navigation":386,"path":1662,"seo":1663,"source":1664,"stem":1665,"__hash__":1666},"docs\u002Fdocs\u002Fschemas\u002Fstorage-shape.md","How values are stored",{"type":7,"value":8,"toc":1630},"minimark",[9,13,25,28,57,62,67,70,156,159,710,714,720,773,788,805,809,814,1009,1012,1016,1022,1143,1160,1164,1176,1185,1238,1241,1249,1286,1296,1304,1347,1364,1368,1557,1576,1580,1626],[10,11,5],"h1",{"id":12},"how-values-are-stored",[14,15,16],"blockquote",{},[17,18,19,20,24],"p",{},"A single mental model for what ",[21,22,23],"code",{},"form.values"," returns. Defaults are pre-resolved, optional \u002F nullable keep their wrappers, and schema-side normalizers (preprocess, coerce, transforms) only fire at parse time. Storage holds the consumer's input verbatim.",[26,27],"docs-meta-table",{},[17,29,30,31,33,34,37,38,41,42,44,45,48,49,52,53,56],{},"The demo below shows the same schema across all three views: what ",[21,32,23],{}," returns at runtime, what ",[21,35,36],{},"setValue"," accepts, and what ",[21,39,40],{},"handleSubmit","'s callback sees. The phone field is the giveaway: storage keeps the raw digits the user typed, and the preprocess formatter's output only surfaces inside ",[21,43,40],{},"'s callback. Preprocess itself runs every time validation does (each keystroke under ",[21,46,47],{},"validateOn: 'change'",", each blur under ",[21,50,51],{},"'blur'",", only at submit under ",[21,54,55],{},"'submit'","), but its output never lands in storage.",[58,59],"docs-demo",{"label":60,"slug":61},"Storage Shape Demo","storage-shape",[63,64,66],"h2",{"id":65},"the-three-shapes","The three shapes",[17,68,69],{},"A schema produces three different views of its data, each with a distinct surface:",[71,72,73,89],"table",{},[74,75,76],"thead",{},[77,78,79,83,86],"tr",{},[80,81,82],"th",{},"Surface",[80,84,85],{},"Shape",[80,87,88],{},"What it answers",[90,91,92,116,136],"tbody",{},[77,93,94,103,109],{},[95,96,97,99,100],"td",{},[21,98,23],{}," \u002F ",[21,101,102],{},"form.fields",[95,104,105],{},[106,107,108],"strong",{},"read",[95,110,111,112,115],{},"What does storage hold now? (",[21,113,114],{},"StorageShape\u003CSchema>",")",[77,117,118,125,130],{},[95,119,120,99,122],{},[21,121,36],{},[21,123,124],{},"defaultValues",[95,126,127],{},[106,128,129],{},"write",[95,131,132,133,115],{},"What may the consumer pass in? (",[21,134,135],{},"z.input\u003CSchema>",[77,137,138,145,150],{},[95,139,140,99,142],{},[21,141,40],{},[21,143,144],{},"form.parse()",[95,146,147],{},[106,148,149],{},"submit",[95,151,152,153,115],{},"What does a successful parse yield? (",[21,154,155],{},"z.output\u003CSchema>",[17,157,158],{},"The same schema produces all three; the surface determines which one you're holding.",[160,161,166],"pre",{"className":162,"code":163,"language":164,"meta":165,"style":165},"language-ts shiki shiki-themes github-light github-dark","const formatPhone = (v: unknown): unknown => {\n  if (typeof v !== 'string') return v\n  const digits = v.replace(\u002F\\D\u002Fg, '')\n  return digits.length === 10\n    ? `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6)}`\n    : v\n}\n\nconst schema = z.object({\n  flag: z.boolean().default(true),\n  count: z.coerce.number(),\n  phone: z.preprocess(formatPhone, z.string()),\n  ratio: z.string().transform((v) => Number(v) \u002F 100),\n})\n\nconst form = useForm({ schema })\n\n\u002F\u002F READ: storage holds the concrete, resolved type\nform.values.flag \u002F\u002F boolean       ← .default(true) peeled\nform.values.count \u002F\u002F unknown        ← z.coerce.X() input is unknown\nform.values.phone \u002F\u002F unknown        ← preprocess input is unknown\nform.values.ratio \u002F\u002F string        ← transform deferred to parse\n\n\u002F\u002F WRITE: anything goes at preprocess \u002F coerce leaves; defaulted leaves accept undefined\nform.setValue('flag', undefined) \u002F\u002F OK; default fills the gap\nform.setValue('count', '42') \u002F\u002F OK; raw string lands in storage as-is\nform.setValue('phone', '1231231234') \u002F\u002F OK; raw digits land in storage as-is\n\n\u002F\u002F SUBMIT: schema-side normalizers fire here\nform.handleSubmit((data) => {\n  data.count \u002F\u002F number ← z.coerce.number() converted at parse\n  data.phone \u002F\u002F string ← preprocess formatted at parse\n  data.ratio \u002F\u002F number ← .transform() produced this\n})\n","ts","",[21,167,168,211,241,281,299,367,375,381,388,407,430,442,460,496,502,507,523,528,535,544,553,562,571,576,582,605,627,649,654,660,678,687,696,705],{"__ignoreMap":165},[169,170,173,177,181,184,188,192,195,199,201,203,205,208],"span",{"class":171,"line":172},"line",1,[169,174,176],{"class":175},"szBVR","const",[169,178,180],{"class":179},"sScJk"," formatPhone",[169,182,183],{"class":175}," =",[169,185,187],{"class":186},"sVt8B"," (",[169,189,191],{"class":190},"s4XuR","v",[169,193,194],{"class":175},":",[169,196,198],{"class":197},"sj4cs"," unknown",[169,200,115],{"class":186},[169,202,194],{"class":175},[169,204,198],{"class":197},[169,206,207],{"class":175}," =>",[169,209,210],{"class":186}," {\n",[169,212,214,217,219,222,225,228,232,235,238],{"class":171,"line":213},2,[169,215,216],{"class":175},"  if",[169,218,187],{"class":186},[169,220,221],{"class":175},"typeof",[169,223,224],{"class":186}," v ",[169,226,227],{"class":175},"!==",[169,229,231],{"class":230},"sZZnC"," 'string'",[169,233,234],{"class":186},") ",[169,236,237],{"class":175},"return",[169,239,240],{"class":186}," v\n",[169,242,244,247,250,252,255,258,261,264,267,269,272,275,278],{"class":171,"line":243},3,[169,245,246],{"class":175},"  const",[169,248,249],{"class":197}," digits",[169,251,183],{"class":175},[169,253,254],{"class":186}," v.",[169,256,257],{"class":179},"replace",[169,259,260],{"class":186},"(",[169,262,263],{"class":230},"\u002F",[169,265,266],{"class":197},"\\D",[169,268,263],{"class":230},[169,270,271],{"class":175},"g",[169,273,274],{"class":186},", ",[169,276,277],{"class":230},"''",[169,279,280],{"class":186},")\n",[169,282,284,287,290,293,296],{"class":171,"line":283},4,[169,285,286],{"class":175},"  return",[169,288,289],{"class":186}," digits.",[169,291,292],{"class":197},"length",[169,294,295],{"class":175}," ===",[169,297,298],{"class":197}," 10\n",[169,300,302,305,308,311,314,317,319,322,324,327,329,332,334,336,338,340,342,344,347,349,352,354,356,358,360,362,364],{"class":171,"line":301},5,[169,303,304],{"class":175},"    ?",[169,306,307],{"class":230}," `(${",[169,309,310],{"class":186},"digits",[169,312,313],{"class":230},".",[169,315,316],{"class":179},"slice",[169,318,260],{"class":230},[169,320,321],{"class":197},"0",[169,323,274],{"class":230},[169,325,326],{"class":197},"3",[169,328,115],{"class":230},[169,330,331],{"class":230},"}) ${",[169,333,310],{"class":186},[169,335,313],{"class":230},[169,337,316],{"class":179},[169,339,260],{"class":230},[169,341,326],{"class":197},[169,343,274],{"class":230},[169,345,346],{"class":197},"6",[169,348,115],{"class":230},[169,350,351],{"class":230},"}-${",[169,353,310],{"class":186},[169,355,313],{"class":230},[169,357,316],{"class":179},[169,359,260],{"class":230},[169,361,346],{"class":197},[169,363,115],{"class":230},[169,365,366],{"class":230},"}`\n",[169,368,370,373],{"class":171,"line":369},6,[169,371,372],{"class":175},"    :",[169,374,240],{"class":186},[169,376,378],{"class":171,"line":377},7,[169,379,380],{"class":186},"}\n",[169,382,384],{"class":171,"line":383},8,[169,385,387],{"emptyLinePlaceholder":386},true,"\n",[169,389,391,393,396,398,401,404],{"class":171,"line":390},9,[169,392,176],{"class":175},[169,394,395],{"class":197}," schema",[169,397,183],{"class":175},[169,399,400],{"class":186}," z.",[169,402,403],{"class":179},"object",[169,405,406],{"class":186},"({\n",[169,408,410,413,416,419,422,424,427],{"class":171,"line":409},10,[169,411,412],{"class":186},"  flag: z.",[169,414,415],{"class":179},"boolean",[169,417,418],{"class":186},"().",[169,420,421],{"class":179},"default",[169,423,260],{"class":186},[169,425,426],{"class":197},"true",[169,428,429],{"class":186},"),\n",[169,431,433,436,439],{"class":171,"line":432},11,[169,434,435],{"class":186},"  count: z.coerce.",[169,437,438],{"class":179},"number",[169,440,441],{"class":186},"(),\n",[169,443,445,448,451,454,457],{"class":171,"line":444},12,[169,446,447],{"class":186},"  phone: z.",[169,449,450],{"class":179},"preprocess",[169,452,453],{"class":186},"(formatPhone, z.",[169,455,456],{"class":179},"string",[169,458,459],{"class":186},"()),\n",[169,461,463,466,468,470,473,476,478,480,483,486,489,491,494],{"class":171,"line":462},13,[169,464,465],{"class":186},"  ratio: z.",[169,467,456],{"class":179},[169,469,418],{"class":186},[169,471,472],{"class":179},"transform",[169,474,475],{"class":186},"((",[169,477,191],{"class":190},[169,479,234],{"class":186},[169,481,482],{"class":175},"=>",[169,484,485],{"class":179}," Number",[169,487,488],{"class":186},"(v) ",[169,490,263],{"class":175},[169,492,493],{"class":197}," 100",[169,495,429],{"class":186},[169,497,499],{"class":171,"line":498},14,[169,500,501],{"class":186},"})\n",[169,503,505],{"class":171,"line":504},15,[169,506,387],{"emptyLinePlaceholder":386},[169,508,510,512,515,517,520],{"class":171,"line":509},16,[169,511,176],{"class":175},[169,513,514],{"class":197}," form",[169,516,183],{"class":175},[169,518,519],{"class":179}," useForm",[169,521,522],{"class":186},"({ schema })\n",[169,524,526],{"class":171,"line":525},17,[169,527,387],{"emptyLinePlaceholder":386},[169,529,531],{"class":171,"line":530},18,[169,532,534],{"class":533},"sJ8bj","\u002F\u002F READ: storage holds the concrete, resolved type\n",[169,536,538,541],{"class":171,"line":537},19,[169,539,540],{"class":186},"form.values.flag ",[169,542,543],{"class":533},"\u002F\u002F boolean       ← .default(true) peeled\n",[169,545,547,550],{"class":171,"line":546},20,[169,548,549],{"class":186},"form.values.count ",[169,551,552],{"class":533},"\u002F\u002F unknown        ← z.coerce.X() input is unknown\n",[169,554,556,559],{"class":171,"line":555},21,[169,557,558],{"class":186},"form.values.phone ",[169,560,561],{"class":533},"\u002F\u002F unknown        ← preprocess input is unknown\n",[169,563,565,568],{"class":171,"line":564},22,[169,566,567],{"class":186},"form.values.ratio ",[169,569,570],{"class":533},"\u002F\u002F string        ← transform deferred to parse\n",[169,572,574],{"class":171,"line":573},23,[169,575,387],{"emptyLinePlaceholder":386},[169,577,579],{"class":171,"line":578},24,[169,580,581],{"class":533},"\u002F\u002F WRITE: anything goes at preprocess \u002F coerce leaves; defaulted leaves accept undefined\n",[169,583,585,588,590,592,595,597,600,602],{"class":171,"line":584},25,[169,586,587],{"class":186},"form.",[169,589,36],{"class":179},[169,591,260],{"class":186},[169,593,594],{"class":230},"'flag'",[169,596,274],{"class":186},[169,598,599],{"class":197},"undefined",[169,601,234],{"class":186},[169,603,604],{"class":533},"\u002F\u002F OK; default fills the gap\n",[169,606,608,610,612,614,617,619,622,624],{"class":171,"line":607},26,[169,609,587],{"class":186},[169,611,36],{"class":179},[169,613,260],{"class":186},[169,615,616],{"class":230},"'count'",[169,618,274],{"class":186},[169,620,621],{"class":230},"'42'",[169,623,234],{"class":186},[169,625,626],{"class":533},"\u002F\u002F OK; raw string lands in storage as-is\n",[169,628,630,632,634,636,639,641,644,646],{"class":171,"line":629},27,[169,631,587],{"class":186},[169,633,36],{"class":179},[169,635,260],{"class":186},[169,637,638],{"class":230},"'phone'",[169,640,274],{"class":186},[169,642,643],{"class":230},"'1231231234'",[169,645,234],{"class":186},[169,647,648],{"class":533},"\u002F\u002F OK; raw digits land in storage as-is\n",[169,650,652],{"class":171,"line":651},28,[169,653,387],{"emptyLinePlaceholder":386},[169,655,657],{"class":171,"line":656},29,[169,658,659],{"class":533},"\u002F\u002F SUBMIT: schema-side normalizers fire here\n",[169,661,663,665,667,669,672,674,676],{"class":171,"line":662},30,[169,664,587],{"class":186},[169,666,40],{"class":179},[169,668,475],{"class":186},[169,670,671],{"class":190},"data",[169,673,234],{"class":186},[169,675,482],{"class":175},[169,677,210],{"class":186},[169,679,681,684],{"class":171,"line":680},31,[169,682,683],{"class":186},"  data.count ",[169,685,686],{"class":533},"\u002F\u002F number ← z.coerce.number() converted at parse\n",[169,688,690,693],{"class":171,"line":689},32,[169,691,692],{"class":186},"  data.phone ",[169,694,695],{"class":533},"\u002F\u002F string ← preprocess formatted at parse\n",[169,697,699,702],{"class":171,"line":698},33,[169,700,701],{"class":186},"  data.ratio ",[169,703,704],{"class":533},"\u002F\u002F number ← .transform() produced this\n",[169,706,708],{"class":171,"line":707},34,[169,709,501],{"class":186},[63,711,713],{"id":712},"two-layers-of-mutation","Two layers of mutation",[17,715,716,717,719],{},"Two distinct surfaces can change what lands in storage. They sit at different boundaries, and ",[21,718,23],{}," reflects only one of them.",[71,721,722,735],{},[74,723,724],{},[77,725,726,729,732],{},[80,727,728],{},"Layer",[80,730,731],{},"Mutates storage?",[80,733,734],{},"When",[90,736,737,754],{},[77,738,739,748,751],{},[95,740,741,744,745],{},[21,742,743],{},"v-register"," modifiers and register ",[21,746,747],{},"transforms",[95,749,750],{},"yes",[95,752,753],{},"at the user-input boundary",[77,755,756,767,770],{},[95,757,758,99,761,99,764],{},[21,759,760],{},"z.preprocess",[21,762,763],{},"z.coerce.X()",[21,765,766],{},".transform(fn)",[95,768,769],{},"no",[95,771,772],{},"at parse \u002F submit",[17,774,775,776,779,780,783,784,787],{},"The directive layer owns write-time mutation: ",[21,777,778],{},"v-register.trim"," strips whitespace as the user blurs, ",[21,781,782],{},"v-register.number"," casts the DOM string to a number, and ",[21,785,786],{},"register({ transforms: [...] })"," runs consumer-supplied functions on every commit. Anything those produce ends up in storage.",[17,789,790,791,794,795,274,797,800,801,804],{},"Schema-side normalizers do their work later, inside ",[21,792,793],{},"safeParse",". The consumer's verbatim write lands in storage; ",[21,796,40],{},[21,798,799],{},"validate",", and ",[21,802,803],{},"validateAsync"," re-parse storage through the schema and surface the typed result. There is no schema shape that mutates storage at the write boundary.",[63,806,808],{"id":807},"per-wrapper-read-shape-policy","Per-wrapper read-shape policy",[17,810,811,813],{},[21,812,114],{}," walks each field and applies one of these rules:",[71,815,816,832],{},[74,817,818],{},[77,819,820,823,826,829],{},[80,821,822],{},"Wrapper",[80,824,825],{},"Field key",[80,827,828],{},"Field type at the key",[80,830,831],{},"Rationale",[90,833,834,857,874,888,909,929,943,960,980,994],{},[77,835,836,841,844,850],{},[95,837,838],{},[21,839,840],{},".default(x)",[95,842,843],{},"required",[95,845,846,847,115],{},"inner type (no ",[21,848,849],{},"| undefined",[95,851,852,853,856],{},"Storage always holds ",[21,854,855],{},"x"," or a write; never empty.",[77,858,859,864,866,869],{},[95,860,861],{},[21,862,863],{},".prefault(x)",[95,865,843],{},[95,867,868],{},"inner type",[95,870,871,872,313],{},"Same as ",[21,873,840],{},[77,875,876,881,883,885],{},[95,877,878],{},[21,879,880],{},".catch(x)",[95,882,843],{},[95,884,868],{},[95,886,887],{},"Catch wraps a fallback; storage holds a value.",[77,889,890,895,898,903],{},[95,891,892],{},[21,893,894],{},".optional()",[95,896,897],{},"optional",[95,899,900],{},[21,901,902],{},"inner | undefined",[95,904,905,906,908],{},"Genuinely optional; ",[21,907,599],{}," is the wrapper's marker.",[77,910,911,916,918,923],{},[95,912,913],{},[21,914,915],{},".nullable()",[95,917,843],{},[95,919,920],{},[21,921,922],{},"inner | null",[95,924,925,928],{},[21,926,927],{},"null"," is the wrapper's \"explicit empty\".",[77,930,931,936,938,940],{},[95,932,933],{},[21,934,935],{},".readonly()",[95,937,843],{},[95,939,868],{},[95,941,942],{},"Read-only is type-only; the read shape is its inner.",[77,944,945,950,952,957],{},[95,946,947],{},[21,948,949],{},"z.preprocess(fn, T)",[95,951,843],{},[95,953,954],{},[21,955,956],{},"unknown",[95,958,959],{},"Schema-side normalizer; runs at parse, not at the write boundary. Storage holds raw input.",[77,961,962,966,968,972],{},[95,963,964],{},[21,965,763],{},[95,967,843],{},[95,969,970],{},[21,971,956],{},[95,973,871,974,976,977,979],{},[21,975,760],{},": coerce fires inside ",[21,978,793],{},". Storage holds whatever the consumer wrote.",[77,981,982,986,988,991],{},[95,983,984],{},[21,985,766],{},[95,987,843],{},[95,989,990],{},"source input shape",[95,992,993],{},"Transforms run at parse, not read; storage holds the pre-transform value.",[77,995,996,999,1001,1006],{},[95,997,998],{},"(plain \u002F fallthrough)",[95,1000,843],{},[95,1002,1003],{},[21,1004,1005],{},"z.input\u003CT>",[95,1007,1008],{},"Default for anything else.",[17,1010,1011],{},"Reads at every nested level get the same treatment recursively.",[63,1013,1015],{"id":1014},"blank-path-synthesis","Blank-path synthesis",[17,1017,1018,1019,1021],{},"Required leaves that haven't been written to aren't ",[21,1020,599],{},". The runtime fills them with the type's falsy concrete at mount:",[71,1023,1024,1037],{},[74,1025,1026],{},[77,1027,1028,1031],{},[80,1029,1030],{},"Schema at path",[80,1032,1033,1034],{},"Initial ",[21,1035,1036],{},"form.values.\u003Cpath>",[90,1038,1039,1050,1061,1073,1085,1097,1109,1121,1133],{},[77,1040,1041,1046],{},[95,1042,1043],{},[21,1044,1045],{},"z.string()",[95,1047,1048],{},[21,1049,277],{},[77,1051,1052,1057],{},[95,1053,1054],{},[21,1055,1056],{},"z.number()",[95,1058,1059],{},[21,1060,321],{},[77,1062,1063,1068],{},[95,1064,1065],{},[21,1066,1067],{},"z.boolean()",[95,1069,1070],{},[21,1071,1072],{},"false",[77,1074,1075,1080],{},[95,1076,1077],{},[21,1078,1079],{},"z.bigint()",[95,1081,1082],{},[21,1083,1084],{},"0n",[77,1086,1087,1092],{},[95,1088,1089],{},[21,1090,1091],{},"z.date()",[95,1093,1094],{},[21,1095,1096],{},"new Date(0)",[77,1098,1099,1104],{},[95,1100,1101],{},[21,1102,1103],{},"z.array(...)",[95,1105,1106],{},[21,1107,1108],{},"[]",[77,1110,1111,1116],{},[95,1112,1113],{},[21,1114,1115],{},"z.set(...)",[95,1117,1118],{},[21,1119,1120],{},"new Set()",[77,1122,1123,1128],{},[95,1124,1125],{},[21,1126,1127],{},"z.record(...)",[95,1129,1130],{},[21,1131,1132],{},"{}",[77,1134,1135,1140],{},[95,1136,1137],{},[21,1138,1139],{},"z.object({...})",[95,1141,1142],{},"recursive: every required property gets its own falsy",[17,1144,1145,1146,1149,1150,1159],{},"The runtime tracks which paths are still \"blank\" through the same field-state bit ",[21,1147,1148],{},"field.blank"," covers; see ",[1151,1152,1154,1155,1158],"a",{"href":1153},"\u002Fdocs\u002Fvalidation\u002Fblank","the ",[21,1156,1157],{},"blank"," field-state bit"," for the storage \u002F display divergence story.",[63,1161,1163],{"id":1162},"three-edges-the-invariant-doesnt-promise-to-flatten","Three edges the invariant doesn't promise to flatten",[17,1165,1166,1167,99,1170,99,1173,1175],{},"These read as honest ",[21,1168,1169],{},"T | undefined",[21,1171,1172],{},"T | null",[21,1174,1169],{}," respectively: documented edges, not bugs.",[1177,1178,1180,1182,1183],"h3",{"id":1179},"optional-no-default-t-undefined",[21,1181,894],{}," (no default): ",[21,1184,1169],{},[160,1186,1188],{"className":162,"code":1187,"language":164,"meta":165,"style":165},"const schema = z.object({ bio: z.string().optional() })\nconst form = useForm({ schema })\n\nform.values.bio \u002F\u002F string | undefined\n",[21,1189,1190,1214,1226,1230],{"__ignoreMap":165},[169,1191,1192,1194,1196,1198,1200,1202,1205,1207,1209,1211],{"class":171,"line":172},[169,1193,176],{"class":175},[169,1195,395],{"class":197},[169,1197,183],{"class":175},[169,1199,400],{"class":186},[169,1201,403],{"class":179},[169,1203,1204],{"class":186},"({ bio: z.",[169,1206,456],{"class":179},[169,1208,418],{"class":186},[169,1210,897],{"class":179},[169,1212,1213],{"class":186},"() })\n",[169,1215,1216,1218,1220,1222,1224],{"class":171,"line":213},[169,1217,176],{"class":175},[169,1219,514],{"class":197},[169,1221,183],{"class":175},[169,1223,519],{"class":179},[169,1225,522],{"class":186},[169,1227,1228],{"class":171,"line":243},[169,1229,387],{"emptyLinePlaceholder":386},[169,1231,1232,1235],{"class":171,"line":283},[169,1233,1234],{"class":186},"form.values.bio ",[169,1236,1237],{"class":533},"\u002F\u002F string | undefined\n",[17,1239,1240],{},"The wrapper's whole point is \"this slot may be absent.\" Storage respects it.",[1177,1242,1244,1246,1247],{"id":1243},"nullable-t-null",[21,1245,915],{},": ",[21,1248,1172],{},[160,1250,1252],{"className":162,"code":1251,"language":164,"meta":165,"style":165},"const schema = z.object({ ref: z.string().nullable() })\nform.values.ref \u002F\u002F string | null\n",[21,1253,1254,1278],{"__ignoreMap":165},[169,1255,1256,1258,1260,1262,1264,1266,1269,1271,1273,1276],{"class":171,"line":172},[169,1257,176],{"class":175},[169,1259,395],{"class":197},[169,1261,183],{"class":175},[169,1263,400],{"class":186},[169,1265,403],{"class":179},[169,1267,1268],{"class":186},"({ ref: z.",[169,1270,456],{"class":179},[169,1272,418],{"class":186},[169,1274,1275],{"class":179},"nullable",[169,1277,1213],{"class":186},[169,1279,1280,1283],{"class":171,"line":213},[169,1281,1282],{"class":186},"form.values.ref ",[169,1284,1285],{"class":533},"\u002F\u002F string | null\n",[17,1287,1288,1290,1291,1293,1294,313],{},[21,1289,927],{}," is the wrapper's \"explicit empty\" signal, distinct from ",[21,1292,599],{}," and from ",[21,1295,277],{},[1177,1297,1299,1300,1246,1302],{"id":1298},"array-element-past-length-t-undefined","Array element past ",[21,1301,292],{},[21,1303,1169],{},[160,1305,1307],{"className":162,"code":1306,"language":164,"meta":165,"style":165},"const schema = z.object({ tags: z.array(z.string()) })\nform.values.tags[0] \u002F\u002F string | undefined\n",[21,1308,1309,1335],{"__ignoreMap":165},[169,1310,1311,1313,1315,1317,1319,1321,1324,1327,1330,1332],{"class":171,"line":172},[169,1312,176],{"class":175},[169,1314,395],{"class":197},[169,1316,183],{"class":175},[169,1318,400],{"class":186},[169,1320,403],{"class":179},[169,1322,1323],{"class":186},"({ tags: z.",[169,1325,1326],{"class":179},"array",[169,1328,1329],{"class":186},"(z.",[169,1331,456],{"class":179},[169,1333,1334],{"class":186},"()) })\n",[169,1336,1337,1340,1342,1345],{"class":171,"line":213},[169,1338,1339],{"class":186},"form.values.tags[",[169,1341,321],{"class":197},[169,1343,1344],{"class":186},"] ",[169,1346,1237],{"class":533},[17,1348,1349,1350,1352,1353,1356,1357,1360,1361,1363],{},"The ",[21,1351,849],{}," taint comes from TypeScript's ",[21,1354,1355],{},"noUncheckedIndexedAccess"," (which strict configs set), not from the storage invariant. Iteration (",[21,1358,1359],{},"for (const tag of form.values.tags)",") keeps the strict ",[21,1362,456],{}," element type; only direct numeric indexing is tainted.",[63,1365,1367],{"id":1366},"when-to-reach-for-which-surface","When to reach for which surface",[160,1369,1371],{"className":162,"code":1370,"language":164,"meta":165,"style":165},"const form = useForm({ schema })\n\n\u002F\u002F READ: anywhere you need the current value\nform.values.email \u002F\u002F primary path\nform.fields.email.value \u002F\u002F same value, plus per-field state\nform.toRef('email') \u002F\u002F ref-shaped interop for external composables\n\n\u002F\u002F WRITE: anywhere you set a value\nform.setValue('email', 'a@b.c') \u002F\u002F single path\nform.setValue({ email: 'a@b.c' }) \u002F\u002F whole-form merge\nform.clear('email') \u002F\u002F wipe to falsy-for-type\nform.reset() \u002F\u002F re-seed from declared defaults\n\n\u002F\u002F SUBMIT: once on form submission\nform.handleSubmit((data) => apiPost(data)) \u002F\u002F `data` is the post-transform output\nconst result = await form.parse() \u002F\u002F imperative one-shot parse\n",[21,1372,1373,1385,1389,1394,1402,1410,1427,1431,1436,1456,1473,1489,1502,1506,1511,1534],{"__ignoreMap":165},[169,1374,1375,1377,1379,1381,1383],{"class":171,"line":172},[169,1376,176],{"class":175},[169,1378,514],{"class":197},[169,1380,183],{"class":175},[169,1382,519],{"class":179},[169,1384,522],{"class":186},[169,1386,1387],{"class":171,"line":213},[169,1388,387],{"emptyLinePlaceholder":386},[169,1390,1391],{"class":171,"line":243},[169,1392,1393],{"class":533},"\u002F\u002F READ: anywhere you need the current value\n",[169,1395,1396,1399],{"class":171,"line":283},[169,1397,1398],{"class":186},"form.values.email ",[169,1400,1401],{"class":533},"\u002F\u002F primary path\n",[169,1403,1404,1407],{"class":171,"line":301},[169,1405,1406],{"class":186},"form.fields.email.value ",[169,1408,1409],{"class":533},"\u002F\u002F same value, plus per-field state\n",[169,1411,1412,1414,1417,1419,1422,1424],{"class":171,"line":369},[169,1413,587],{"class":186},[169,1415,1416],{"class":179},"toRef",[169,1418,260],{"class":186},[169,1420,1421],{"class":230},"'email'",[169,1423,234],{"class":186},[169,1425,1426],{"class":533},"\u002F\u002F ref-shaped interop for external composables\n",[169,1428,1429],{"class":171,"line":377},[169,1430,387],{"emptyLinePlaceholder":386},[169,1432,1433],{"class":171,"line":383},[169,1434,1435],{"class":533},"\u002F\u002F WRITE: anywhere you set a value\n",[169,1437,1438,1440,1442,1444,1446,1448,1451,1453],{"class":171,"line":390},[169,1439,587],{"class":186},[169,1441,36],{"class":179},[169,1443,260],{"class":186},[169,1445,1421],{"class":230},[169,1447,274],{"class":186},[169,1449,1450],{"class":230},"'a@b.c'",[169,1452,234],{"class":186},[169,1454,1455],{"class":533},"\u002F\u002F single path\n",[169,1457,1458,1460,1462,1465,1467,1470],{"class":171,"line":409},[169,1459,587],{"class":186},[169,1461,36],{"class":179},[169,1463,1464],{"class":186},"({ email: ",[169,1466,1450],{"class":230},[169,1468,1469],{"class":186}," }) ",[169,1471,1472],{"class":533},"\u002F\u002F whole-form merge\n",[169,1474,1475,1477,1480,1482,1484,1486],{"class":171,"line":432},[169,1476,587],{"class":186},[169,1478,1479],{"class":179},"clear",[169,1481,260],{"class":186},[169,1483,1421],{"class":230},[169,1485,234],{"class":186},[169,1487,1488],{"class":533},"\u002F\u002F wipe to falsy-for-type\n",[169,1490,1491,1493,1496,1499],{"class":171,"line":444},[169,1492,587],{"class":186},[169,1494,1495],{"class":179},"reset",[169,1497,1498],{"class":186},"() ",[169,1500,1501],{"class":533},"\u002F\u002F re-seed from declared defaults\n",[169,1503,1504],{"class":171,"line":462},[169,1505,387],{"emptyLinePlaceholder":386},[169,1507,1508],{"class":171,"line":498},[169,1509,1510],{"class":533},"\u002F\u002F SUBMIT: once on form submission\n",[169,1512,1513,1515,1517,1519,1521,1523,1525,1528,1531],{"class":171,"line":504},[169,1514,587],{"class":186},[169,1516,40],{"class":179},[169,1518,475],{"class":186},[169,1520,671],{"class":190},[169,1522,234],{"class":186},[169,1524,482],{"class":175},[169,1526,1527],{"class":179}," apiPost",[169,1529,1530],{"class":186},"(data)) ",[169,1532,1533],{"class":533},"\u002F\u002F `data` is the post-transform output\n",[169,1535,1536,1538,1541,1543,1546,1549,1552,1554],{"class":171,"line":509},[169,1537,176],{"class":175},[169,1539,1540],{"class":197}," result",[169,1542,183],{"class":175},[169,1544,1545],{"class":175}," await",[169,1547,1548],{"class":186}," form.",[169,1550,1551],{"class":179},"parse",[169,1553,1498],{"class":186},[169,1555,1556],{"class":533},"\u002F\u002F imperative one-shot parse\n",[17,1558,1559,1560,1563,1564,1566,1567,1569,1570,1572,1573,1575],{},"Each surface uses the shape that's correct for its purpose. The mental discipline: ",[106,1561,1562],{},"don't reach across surfaces."," If you want post-transform output, go through submit. If you want the raw input, go through ",[21,1565,23],{},". If you want to write, go through ",[21,1568,36],{}," or ",[21,1571,1479],{},"; ",[21,1574,23],{}," is read-only on purpose.",[63,1577,1579],{"id":1578},"where-to-next","Where to next",[1581,1582,1583,1595,1602,1616],"ul",{},[1584,1585,1586,1590,1591,1594],"li",{},[1151,1587,1589],{"href":1588},"\u002Fdocs\u002Fschemas\u002Fdefaults","Defaults from the schema",": how ",[21,1592,1593],{},".default()"," flows into the read shape.",[1584,1596,1597,1601],{},[1151,1598,1600],{"href":1599},"\u002Fdocs\u002Fschemas\u002Foptional-nullable","Optional, nullable, defaulted",": the three missing-ness modifiers, side by side.",[1584,1603,1604,1608,1609,1611,1612,1615],{},[1151,1605,1607],{"href":1606},"\u002Fdocs\u002Fvalidation\u002Furl-availability-check","URL availability check",": a worked example threading ",[21,1610,760],{}," and async ",[21,1613,1614],{},".refine"," against the storage contract.",[1584,1617,1618,1246,1622,1625],{},[1151,1619,1621],{"href":1620},"\u002Fdocs\u002Fvalidation\u002Flifecycle","The validation lifecycle",[21,1623,1624],{},"parse()"," returns the submit shape, parsed.",[1627,1628,1629],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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":165,"searchDepth":213,"depth":213,"links":1631},[1632,1633,1634,1635,1636,1644,1645],{"id":65,"depth":213,"text":66},{"id":712,"depth":213,"text":713},{"id":807,"depth":213,"text":808},{"id":1014,"depth":213,"text":1015},{"id":1162,"depth":213,"text":1163,"children":1637},[1638,1640,1642],{"id":1179,"depth":243,"text":1639},".optional() (no default): T | undefined",{"id":1243,"depth":243,"text":1641},".nullable(): T | null",{"id":1298,"depth":243,"text":1643},"Array element past length: T | undefined",{"id":1366,"depth":213,"text":1367},{"id":1578,"depth":213,"text":1579},"form.values exposes the storage shape, the consumer's raw input with defaults resolved. Schema-side normalizers (preprocess, coerce, transforms) run at parse, not at the write boundary. handleSubmit gets the post-parse output.","md",{},[1650,1653,1656,1659],{"label":1651,"value":1652},"Category","Conceptual",{"label":1654,"value":1655,"kind":21},"Read shape","form.values, form.fields",{"label":1657,"value":1658,"kind":21},"Write shape","setValue, defaultValues",{"label":1660,"value":1661,"kind":21},"Submit shape","handleSubmit, form.parse()","\u002Fdocs\u002Fschemas\u002Fstorage-shape",{"title":5,"description":1646},null,"docs\u002Fschemas\u002Fstorage-shape","JdRb_l-396Q1LfsiRul4v7ZNLCFx5hDN-OdtqxcMyKk",1780949757609]