Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
257 changes: 0 additions & 257 deletions notebook/skip-uniontotuple-optimization.md

This file was deleted.

47 changes: 43 additions & 4 deletions src/infer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,48 @@ type InferRecord<T> = T extends { record: infer R }
: unknown
: unknown;

type InferDefs<T extends Record<string, unknown>> = {
-readonly [K in keyof T]: InferType<T[K]>;
};
/**
* Recursively replaces stub references in a type with their actual definitions.
* Detects circular references and missing references, returning string literal error messages.
*/
type ReplaceRefsInType<T, Defs, Visited = never> =
// Check if this is a ref stub type (has $type starting with #)
T extends { $type: `#${infer DefName}` }
? DefName extends keyof Defs
? // Check for circular reference
DefName extends Visited
? `[Circular reference detected: #${DefName}]`
: // Recursively resolve the ref and preserve the $type marker
Prettify<
ReplaceRefsInType<Defs[DefName], Defs, Visited | DefName> & {
$type: T["$type"];
}
>
: // Reference not found in definitions
`[Reference not found: #${DefName}]`
: // Handle arrays (but not Uint8Array or other typed arrays)
T extends Uint8Array | Blob
? T
: T extends readonly (infer Item)[]
? ReplaceRefsInType<Item, Defs, Visited>[]
: // Handle plain objects (exclude built-in types and functions)
T extends object
? T extends (...args: unknown[]) => unknown
? T
: { [K in keyof T]: ReplaceRefsInType<T[K], Defs, Visited> }
: // Primitives pass through unchanged
T;

/**
* Infers the TypeScript type for a lexicon namespace, returning only the 'main' definition
* with all local refs (#user, #post, etc.) resolved to their actual types.
*/
export type Infer<T extends { id: string; defs: Record<string, unknown> }> =
Prettify<InferDefs<T["defs"]>>;
Prettify<
"main" extends keyof T["defs"]
? { $type: T["id"] } & ReplaceRefsInType<
InferType<T["defs"]["main"]>,
{ [K in keyof T["defs"]]: InferType<T["defs"][K]> }
>
: never
>;
Loading