typescript-extract-type-json.ts

Structured type extraction — builds TypeJson trees from checker types.

Also the home of the checker-policy primitives the sibling extractors consume: optionalWideningTarget (the one owner of the optional-widening strip — getTypeSignature and getNonOptionalType in typescript-extract-shared.ts select through it, so the flat string, the tree, and the structural queries can't drift), referenceSymbolName (the named-generic-instantiation predicate, shared with isSnippetType in svelte.ts), and tupleElements/tupleElementName/restElementForms (the one tuple-element walk, naming rule, and rest-element projection, shared with extractSnippetParameters). resolveTypeInfo builds the tree and applies the TypeJson absence contract — returning undefined when the node carries no structure beyond the flat string. It also owns name recovery for types whose alias TypeScript dropped (an alias over an indexed access or conditional — z.infer<typeof S>, valibot's InferOutput), through two composed channels consulted only at nameless positions: written-name recovery (a caller-supplied annotation node feeds a type-identity map, buildWrittenNameMap) and the identity-keyed alias registry (AliasRegistry, built by buildAliasRegistry in typescript-alias-registry.ts over the analyzed set's exported lost aliases). Where either names the type, the tree emits {kind: 'reference', name} instead of the structure the checker would print. The written channel wins when both match; the registry is additionally suppressed at the root of a type-alias declaration's own site (the self-skip — a lost alias carries no aliasSymbol, so without it the declaration's own typeInfo would collapse to a self-reference, or under ambiguity a reference to its twin; nested self-hits stay live and terminate recursive types with a name). Expansion, alias, and normalization policy live on the TypeJson schema doc in types.ts.

@internal Used by the extractors — not part of the public barrel export.

view source

Declarations
#

16 declarations

AliasRegistry
#

typescript-extract-type-json.ts view source

AliasRegistry import type {AliasRegistry} from 'svelte-docinfo/typescript-extract-type-json.js';

Identity-keyed registry of exported alias-lost type aliases, consulted by the tree builder at nameless positions behind written-name recovery. Built per analysis cycle by buildAliasRegistry (typescript-alias-registry.ts); undefined wherever no pre-pass ran (registry recovery disabled, written recovery unaffected).

byType

Checker type identity → the winning alias (compareStrings name-then-module tie-break).

type Map<Type, AliasRegistryEntry>

byMemberSet

Union member-set key (unionMemberSetKey) → the winning alias, for registered unions only. Consulted at optional-widened positions, where a null-bearing union flattens with the widening undefined into a type object the identity lookup can never match — the registered members survive by identity inside the widened union, so the set matches exactly.

type Map<string, AliasRegistryEntry>

warnedAliasLost

Alias declarations the alias_lost warning has fired for this cycle. Re-export synthesis re-analyzes canonical declarations (synthesizeCrossFileAlias, within-file renames), so one declaration can reach warnAliasLost from several analyzing sites in a cycle — this set dedupes to one warning per declaration. It rides on the registry because the registry is the one cycle-scoped object every warn site already holds (the warning is gated on a registry being in hand).

type Set<TypeAliasDeclaration>

AliasRegistryEntry
#

isAliasLostType
#

typescript-extract-type-json.ts view source

(type: Type): boolean import {isAliasLostType} from 'svelte-docinfo/typescript-extract-type-json.js';

Whether the checker kept no name for a type-alias declaration's resolved type: no alias symbol (the checker still prints type A = B as B), no nominal symbol (interfaces/classes/enums print their own name), and not an interned terminal (type A = string and type A = 'x' carry no alias symbol either but print fine). True exactly for the expansion-prone class the alias registry targets and the alias_lost diagnostic reports — indexed-access and conditional right-hand sides (z.infer<typeof S> et al.), whose resolution lands on a pre-existing interned type that TypeScript never retroactively stamps an alias symbol on.

type

type Type

returns

boolean

isBrandLikeIntersection
#

typescript-extract-type-json.ts view source

(type: Type): boolean import {isBrandLikeIntersection} from 'svelte-docinfo/typescript-extract-type-json.js';

Whether a type is an intersection carrying an intrinsic or literal member — the .brand() shape (string & BRAND<'x'>). Such aliases are lost but unrecoverable, readable, and author-unfixable, so the alias_lost diagnostic excludes them.

type

type Type

returns

boolean

isLiteralOnlyUnion
#

typescript-extract-type-json.ts view source

(type: Type): boolean import {isLiteralOnlyUnion} from 'svelte-docinfo/typescript-extract-type-json.js';

Whether a type is a union of literals only (z.enum outputs — a lost alias over one degrades mildly and readably, so the alias_lost diagnostic excludes it). Enum-member literals match too.

type

type Type

returns

boolean

namedSymbolName
#

typescript-extract-type-json.ts view source

(type: Type): string | undefined import {namedSymbolName} from 'svelte-docinfo/typescript-extract-type-json.js';

The type's non-anonymous symbol name (__type/__object/__function mark anonymous shapes). The one anonymity rule shared by the recovery gate here, the alias-lost predicate (isAliasLostType), and the registry's safety-gate walk (typescript-alias-registry.ts) — never ObjectFlags.Anonymous, which real inferred schema outputs (zod's are Mapped | Instantiated) don't carry.

type

type Type

returns

string | undefined

optionalWideningTarget
#

typescript-extract-type-json.ts view source

(type: Type, checker: TypeChecker, optional: boolean): { target: Type; dropUndefined: boolean; } import {optionalWideningTarget} from 'svelte-docinfo/typescript-extract-type-json.js';

The single owner of the optional-widening strip, shared with getTypeSignature and getNonOptionalType (in typescript-extract-shared.ts) so the flat string, the tree, and the structural queries can't drift. Owns the optional gate too — a non-optional position passes through, so call sites hand over the flag rather than branching around the call. For a type at an optional-flagged position (a ?-marked declaration or tuple element):

  • a non-union carries no separate widening member to strip, so it passes through. Three shapes land here: x?: undefined (the written type and the widening coincide), and x?: unknown / x?: any (both absorb undefined). getNonNullableType must not run on any of them — it answers {} for unknown, which would report x?: unknown as "{}"
  • a null-bearing union keeps its shape and reports dropUndefined — the walk drops only the widening member (so the alias survives) and the printer trims the printed suffix
  • a union left with exactly one member after dropping undefined takes that member directly — it *is* the annotated type. Matters for a bare unconstrained type parameter (c?: E), where getNonNullableType can only answer NonNullable<E> and would print E & {}
  • every other union takes getNonNullableType, which rebuilds the union rather than picking a member (so a union of callables keeps its combined call signature) and preserves the alias symbol

Under exactOptionalPropertyTypes the checker widens optional *properties* not at all, so property sites gate optional off via optionalWidened (in typescript-extract-shared.ts) and never reach the strip; optional parameters and tuple elements widen under both modes and keep passing optional unconditionally.

type

type Type

checker

type TypeChecker

optional

type boolean

returns

{ target: Type; dropUndefined: boolean; }

referenceSymbolName
#

typescript-extract-type-json.ts view source

(type: Type, checker: TypeChecker): string | undefined import {referenceSymbolName} from 'svelte-docinfo/typescript-extract-type-json.js';

The symbol name of a named generic instantiation (Snippet<[a: string]>, Map<string, B>) — checker Reference-flagged, non-anonymous symbol, carrying type arguments — or undefined for everything else. One predicate for the two decisions that must agree: the callable-classification exception (such a type is a reference node even when it has call signatures) and the object branch's reference emission. Tuples never match (their references carry no symbol); bare and aliased signatures are Anonymous-flagged; non-generic callable interfaces either aren't Reference-flagged (thisless) or carry no type arguments (the declared type of a this-referencing interface or a class is its own Reference with an empty argument list) — all of these stay function nodes.

type

type Type

checker

type TypeChecker

returns

string | undefined

resolveTypeInfo
#

typescript-extract-type-json.ts view source

(type: Type, checker: TypeChecker, aliasRegistry: AliasRegistry | undefined, optional: boolean, options?: ResolveTypeInfoOptions | undefined): TypeJson | undefined import {resolveTypeInfo} from 'svelte-docinfo/typescript-extract-type-json.js';

The structured type for an output field, or undefined when the flat string is the whole story (the TypeJson absence contract).

Matches getTypeSignature's optional handling by construction — both select through optionalWideningTarget (see there for the case split); x?: undefined stays terminal. What's specific to the tree: union members walk the union's origin (see unionMemberTypes), so member order matches the printed string and a null-bearing optional alias survives: dropping the widening from the origin list leaves the alias-carrying union as the sole member, which the 1-member collapse promotes to the root (a?: A where A is nullable yields the A union, matching the flat string's printed-string surgery). When no usable origin exists both degrade together, bounded: checker- internal member order, alias lost.

Self-named alias roots relax the contract. checker.typeToString prints a type carrying an alias symbol as that alias's bare name, so a type alias's own typeSignature reads "StrArr", not "string[]" — there is no descriptive flat sibling for the tree to defer to, and the usual gate would leave type StrArr = string[] and type Pair = [string, number] with no type information at all. When the type reports ownAliasName as its alias the node is emitted regardless, except for the kinds members already covers (REDUNDANT_WITH_MEMBERS). Interned types (intrinsics, literals) never carry the alias symbol, so type Str = string still prints structurally and stays absent.

Recovered roots relax it too. When writtenNode or aliasRegistry names a nameless type, the tree emits {kind: 'reference', name} (see buildWrittenNameMap / recoveredReference) — and at the root that node is emitted even though a bare reference normally stays absent: a checker-named bare reference defers to a flat sibling printing the same name, while a recovered one stands against a flat sibling printing the anonymous expansion, so the name exists only in the tree.

type

the checker type the flat string was printed from

type Type

checker

TypeScript type checker

type TypeChecker

aliasRegistry

the analyzed set's alias registry, or undefined when no pre-pass ran; required so a call site can't silently opt out of registry recovery

type AliasRegistry | undefined

optional

whether the declaration site carries a ? token (pairs the widening strip, like getTypeSignature)

type boolean

options?

the declaration-site context: ownAliasName at a type-alias declaration (see BuildTypeJsonOptions.skipAliasName; also suppresses registry hits at the root — the self-skip), writtenNode wherever a written annotation exists (the name-recovery source for aliases TypeScript dropped)

optional

returns

TypeJson | undefined

ResolveTypeInfoOptions
#

typescript-extract-type-json.ts view source

ResolveTypeInfoOptions import type {ResolveTypeInfoOptions} from 'svelte-docinfo/typescript-extract-type-json.js';

Declaration-site context for resolveTypeInfo — see its param doc.

ownAliasName?

At a type-alias declaration site, the alias's own name.

type string

writtenNode?

The declaration's written type annotation, when one exists.

type TypeNode

restElementForms
#

typescript-extract-type-json.ts view source

(elementType: Type, checker: TypeChecker, aliasRegistry: AliasRegistry | undefined, writtenNode?: TypeNode | undefined): { ...; } import {restElementForms} from 'svelte-docinfo/typescript-extract-type-json.js';

Both output forms of a rest tuple element, which present it as the array it collects (...rest: B[] carries "B[]" and an array node) — the flat/structured counterpart of buildTuple's array rewrap, for extractSnippetParameters. Paired in one function so the two can't be half applied: a printed array beside a non-array tree would describe two different types.

The string prints through the checker's internal createArrayType so parenthesization is the printer's own — hand rules get the edges wrong (a readonly B[] element *must* parenthesize or readonly B[][] denotes a different type, a bare union needs parens, a unique symbol prints as a typeof query). If the internal factory disappears, the fallback parenthesizes everything but bare identifier paths — sometimes over-parenthesized, never a different type. The tree is presence-gated like any array node (present when the element is a reference or carries structure). writtenNode and aliasRegistry feed name recovery like resolveTypeInfo's — the caller passes the same annotation and registry it hands the sibling tree, so the two projections of one element can't disagree on a recovered name.

elementType

type Type

checker

type TypeChecker

aliasRegistry

type AliasRegistry | undefined

writtenNode?

type TypeNode
optional

returns

{ type: string; typeInfo: TypeJson | undefined; }

specifierExportedName
#

typescript-extract-type-json.ts view source

(symbol: Symbol): string | undefined import {specifierExportedName} from 'svelte-docinfo/typescript-extract-type-json.js';

The name a module exports an aliased symbol under, or undefined when the alias names no export (a default or namespace import, a star re-export).

The one rule shared by both name-recovery channels — this file's written-name lookup and externalTypeRefText's textual substitution (typescript-extract-shared.ts). Both specifier kinds carry the name, on opposite sides of their own as: an ImportSpecifier takes the module's side, its propertyName (import type {Bag as B}Bag, B being this file's private spelling), while an ExportSpecifier *is* the module's side, so its name is what it publishes (export {Internal as Public}Public, Internal being the other module's). Unrenamed, both collapse to the one name written.

Stopping at a specifier rather than resolving the whole alias chain is what makes the result importable: the chain ends at the *declaration's* name, which a module renaming on the way out never exports — recovering Internal there names something no consumer of that module can reach.

symbol

type Symbol

returns

string | undefined

tupleElementName
#

typescript-extract-type-json.ts view source

(el: TupleTypeElement): string | undefined import {tupleElementName} from 'svelte-docinfo/typescript-extract-type-json.js';

The written element label as an output name: a NamedTupleMember's identifier, or a parameter-derived label's (Parameters<F> tuples) — the identifier guard is defensive, since binding-pattern parameters produce no label declaration at all. The one naming rule for both tupleElements consumers, so parameters and the typeInfo tree can't disagree on names.

el

returns

string | undefined

tupleElements
#

typescript-extract-type-json.ts view source

(type: TypeReference, checker: TypeChecker): TupleTypeElement[] import {tupleElements} from 'svelte-docinfo/typescript-extract-type-json.js';

The per-index element metadata of a tuple reference — the one place the typeArguments/elementFlags/labeledElementDeclarations triple is read, consumed by buildTuple here and extractSnippetParameters in svelte.ts.

type

type TypeReference

checker

type TypeChecker

returns

TupleTypeElement[]

TupleTypeElement
#

typescript-extract-type-json.ts view source

TupleTypeElement import type {TupleTypeElement} from 'svelte-docinfo/typescript-extract-type-json.js';

Per-element checker metadata from tupleElements — one walk, projected per consumer.

type

The element's type argument; widened with undefined when optional.

type Type

label

The written label declaration, when the tuple has one for this slot.

type NamedTupleMember | ParameterDeclaration | undefined

optional

Whether the element carries a ? marker.

type boolean

rest

Whether the element is a rest element (...boolean[]; type is the array *element* type).

type boolean

variadic

Whether the element is an unresolved variadic spread (...T; type is the spread type).

type boolean

unionMemberSetKey
#

typescript-extract-type-json.ts view source

(type: UnionType): string | undefined import {unionMemberSetKey} from 'svelte-docinfo/typescript-extract-type-json.js';

The member-set key of a union — sorted internal type ids, undefined filtered — or undefined when unusable (an internal-API id missing, or fewer than two non-undefined members, a set no widened-union lookup can produce). One function for both sides so registration and lookup can't drift. Identity safety carries over from the ids: two unions share a key only when they share their non-undefined members by object identity.

type

type UnionType

returns

string | undefined

Depends on
#

Imported by
#