{"record":{"id":"2f47526931485d10","repo":"can1357/oh-my-pi","slug":"thunk-must-return-a-type-was-typeof-resolved","errorCode":null,"errorMessage":"thunk must return a Type (was ${typeof resolved})","messagePattern":"thunk must return a Type \\(was (.+?)\\)","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/ir.ts","lineNumber":1516,"sourceCode":"\t\t}\n\t\tif (parsed.optional) {\n\t\t\tthrow new OmpTypeError(`optional \"?\" marker is only valid on object property values`);\n\t\t}\n\t\treturn parsed.ir;\n\t}\n\tif (Array.isArray(def)) {\n\t\tif (def.length === 3 && def[1] === \"=\") {\n\t\t\tthrow new OmpTypeError(\"A default may only be specified for an object property or tuple element\");\n\t\t}\n\t\treturn parseArrayExpression(def, resolve);\n\t}\n\tif (def instanceof RegExp) return patternIR(def);\n\tif (def instanceof Date) return { k: \"lit\", v: def };\n\tif (isEmbedded(def)) return embed(def);\n\tif (typeof def === \"function\") {\n\t\tconst resolved = Reflect.apply(def, undefined, []);\n\t\tif (!isEmbedded(resolved)) {\n\t\t\tthrow new OmpTypeError(`thunk must return a Type (was ${typeof resolved})`);\n\t\t}\n\t\treturn embed(resolved);\n\t}\n\tif (isObjectDefinition(def)) return parseObjectDefinition(def, resolve);\n\tthrow new OmpTypeError(`unsupported definition ${String(def)} (was ${typeof def})`);\n}\n\n/** Whether `ir` needs no construction-time normalization or morph analysis. */\nexport function isSimpleIR(ir: IR): boolean {\n\tconst cached = ir[kSimpleOwner] === ir ? ir[kSimple] : undefined;\n\tif (cached !== undefined) return cached;\n\tconst simple = scanSimpleIR(ir);\n\tir[kSimple] = simple;\n\tir[kSimpleOwner] = ir;\n\treturn simple;\n}\n\nfunction scanSimpleIR(ir: IR): boolean {","sourceCodeStart":1498,"sourceCodeEnd":1534,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/ir.ts#L1498-L1534","documentation":"Function definitions in omptype are thunks: zero-argument functions lazily producing a type/embeddable schema. parseDef invokes the thunk with Reflect.apply(def, undefined, []) and requires the return value to satisfy isEmbedded; anything else (string, number, plain object, undefined, class instance) triggers this error naming the typeof the bad return value.","triggerScenarios":"Passing a function to type()/parseDef whose body returns something other than a Type/embeddable schema — e.g. returning a raw string definition instead of calling type() on it, returning undefined from a forgetful thunk, or a memoized getter returning a cached non-type value.","commonSituations":"Recursive type helpers where the thunk returns def data instead of a parsed type; lazy imports resolving to the wrong export; typos like () => \"string\" instead of () => type(\"string\").","solutions":["Return a Type from the thunk: () => type(\"string\") rather than () => \"string\"","Ensure lazy/async-loaded values are fully constructed types before returning","Check memoization wrappers preserve the Type instance","Inspect the reported typeof in the message to identify what was actually returned"],"exampleFix":"// before\nconst T = type(() => \"string|number\")\n// after\nconst T = type(() => type(\"string|number\"))","handlingStrategy":"type-guard","validationCode":"function assertThunkReturnsType(fn) {\n  if (typeof fn !== \"function\") return;\n  const r = fn();\n  if (r == null || typeof r !== \"object\")\n    throw new Error(\"thunk must return a Type, not \" + typeof r);\n}","typeGuard":"const returnsType = (fn) => { try { const r = fn(); return r != null && typeof r === \"object\"; } catch { return false; } };","tryCatchPattern":"try { const T = type(thunk); } catch (e) {\n  if (String(e.message).startsWith(\"thunk must return a Type\")) {\n    // wrap the thunk body's return in type(...) and retry\n  } else throw e;\n}","preventionTips":["Always return type(...) results from thunks, never raw def strings or plain values","Check lazy imports resolve to constructed types, not def data","Add a unit test exercising each recursive/lazy thunk"],"tags":["omptype","thunk","schema-definition","lazy-type"],"backgroundTag":"invalid-thunk-return","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}