You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add typeref(Type) for embedding references to compiler types in metadata values, using native, cached scalar TypeRef<T = unknown> storage and TypeSpec assignability checks.
Gate function calls with the default-off typeref compiler feature in the calling project or library. Export TypeRefType, TypeRefValue, and isTypeRefType from @typespec/compiler; there is no TypeRef-specific experimental subpackage.
Map native reference storage and metadata reference values through mutation, preserving the storage annotation separately from the precise target. Include reference-containing decorator values, defaults, scalar constructor arguments, and template arguments.
Treat references as compilation metadata rather than runtime JSON values, with TypeRef-specific schema handling.
The standard-library function declaration retains a declaration-local #suppress "experimental-feature" for the separate function-declaration warning. Function use is controlled by the typeref feature flag.
Implementation scope
TypeRef is not a new intrinsic type kind or runtime intrinsic scalar. Its factory resolves the native declaration and uses the compiler's existing instantiation cache. TypeRef-specific assignability remains in areScalarsRelated.
Mutation adds direct TypeRef handling while preserving the existing traversal helpers and lazy-clone behavior. Native storage uses the canonical factory; reference values map both their original annotation and precise target. Reference-containing template mappers keep args, map, and getMappedType consistent, including mixed type/value arguments.
The pre-existing lazy-owner and recursive lazy-clone issues are explicitly outside this PR's scope; this does not claim to fix those graphs. See #7003.
Existing handling of non-representable examples, defaults, and extension values is unchanged. General serialization-error recovery, example filtering, and first-serializable-example selection are outside this PR's scope.
Emitter integration
GraphQL: diagnose references in emitted fields, root operations, and attached output-object operations, including external @operationFields resolvers. Ignore operations and metadata models that are not rendered.
OpenAPI 3: inline native reference types as schemas accepting no JSON values. Existing example serialization is unchanged.
JSON Schema: keep native reference schemas inline and represent them as accepting no JSON values. Existing default, example, and extension serialization is unchanged.
Full workspace build: 48 successful tasks, followed by engineering checks and compiler signature regeneration. The complete test suite passed: 10,678 tests passed and 25 skipped. Full formatting, format verification, and strict type-aware lint passed. Spelling checks passed for all 39 files in the TypeRef diff.
Introduce typeref as an experimental function returning TypeRefValue metadata with unknown storage type. Preserve compiler type identity through nested values, JavaScript calls, and mutation, and reject JSON serialization.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9d925ae2-0253-4c4d-a87b-49740d9ef737
Correct reflection type constraint comparisons in function signatures, template parameters, and type references so namespace and other non-model constraints are not accepted as model constraints.
Add typeref(Type) for referencing types from metadata values. Enable the typeref compiler feature in the calling project or library's tspconfig.yaml. Its result has type TypeRef<T>, where T is the referenced type. Use TypeRef to accept any type reference, or TypeRef<T> to constrain its target. JavaScript implementations and generated signatures use TypeRefValue from @typespec/compiler, whose target is the referenced compiler type. Type references are compilation metadata and cannot be represented as JSON values.,> ,> typespec,> model Item { id: string; },> model Registration { name: string; type: TypeRef; },> const entry: Registration = #{ name: "item", type: typeref(Item) };,>
Add typeref(Type) for referencing types from metadata values. Enable the typeref compiler feature in the calling project or library's tspconfig.yaml. Its result has type TypeRef<T>, where T is the referenced type. Use TypeRef to accept any type reference, or TypeRef<T> to constrain its target. JavaScript implementations and generated signatures use TypeRefValue from @typespec/compiler, whose target is the referenced compiler type. Type references are compilation metadata and cannot be represented as JSON values.,> ,> typespec,> model Item { id: string; },> model Registration { name: string; type: TypeRef; },> const entry: Registration = #{ name: "item", type: typeref(Item) };,>
Add typeref(Type) for referencing types from metadata values. Enable the typeref compiler feature in the calling project or library's tspconfig.yaml. Its result has type TypeRef<T>, where T is the referenced type. Use TypeRef to accept any type reference, or TypeRef<T> to constrain its target. JavaScript implementations and generated signatures use TypeRefValue from @typespec/compiler, whose target is the referenced compiler type. Type references are compilation metadata and cannot be represented as JSON values.,> ,> typespec,> model Item { id: string; },> model Registration { name: string; type: TypeRef; },> const entry: Registration = #{ name: "item", type: typeref(Item) };,>
Add typeref(Type) for referencing types from metadata values. Enable the typeref compiler feature in the calling project or library's tspconfig.yaml. Its result has type TypeRef<T>, where T is the referenced type. Use TypeRef to accept any type reference, or TypeRef<T> to constrain its target. JavaScript implementations and generated signatures use TypeRefValue from @typespec/compiler, whose target is the referenced compiler type. Type references are compilation metadata and cannot be represented as JSON values.,> ,> typespec,> model Item { id: string; },> model Registration { name: string; type: TypeRef; },> const entry: Registration = #{ name: "item", type: typeref(Item) };,>
Add typeref(Type) for referencing types from metadata values. Enable the typeref compiler feature in the calling project or library's tspconfig.yaml. Its result has type TypeRef<T>, where T is the referenced type. Use TypeRef to accept any type reference, or TypeRef<T> to constrain its target. JavaScript implementations and generated signatures use TypeRefValue from @typespec/compiler, whose target is the referenced compiler type. Type references are compilation metadata and cannot be represented as JSON values.,> ,> typespec,> model Item { id: string; },> model Registration { name: string; type: TypeRef; },> const entry: Registration = #{ name: "item", type: typeref(Item) };,>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Type references remain pointed at original types after mutation in scalar constructor arguments, template arguments, and decorators on lazily cloned models.
Traverse scalar constructor and template value arguments, preserve remapped metadata on lazily cloned owners, and keep template-map accessors consistent with remapped values. Add focused regression coverage for the three verified Copilot review findings.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9d925ae2-0253-4c4d-a87b-49740d9ef737
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Filtered-default traversal fails to propagate a lazily cloned property into the cloned model, leaving a reference to unmutated Item and requiring a fix with regression coverage.
No open issues 🎉
1 previously missed issue
In code that hasn't changed since last review
Propagate cloned properties into lazily cloned models
With Model.filter: m => m.name === "Item" and model Foo { itemType: unknown = typeref(Item); }, this traversal lazily clones both Foo and its property, but mutateSubMap still uses the original mutating === false (mutators.ts:916–920), so the returned model retains the original property and its reference to unmutated Item. Please propagate the cloned property into the lazily cloned model using the live mutation state, and add a regression covering this filtered-default case.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Reachable TypeRef references can produce undeclared GraphQL types, and unserializable TypeRef defaults can crash JSON Schema emission instead of reporting diagnostics.
Emitting model Item {} model Registration { type: TypeRef = typeref(Item); } still crashes: modelPropertyLiteral calls #getDefaultValue (json-schema-emitter.ts:319–334), which lets the new UnserializableValueError escape instead of reporting an invalid default. Catch and report unserializable values at the emitter's default/example serialization boundaries, as OpenAPI3 already does for defaults in packages/openapi3/src/util.ts:160–172, and add an emitter regression.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Uncaught TypeRef serialization errors can abort CLI compilation, while missing mutation support preserves stale references and GraphQL union traversal can incorrectly suppress schema output.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
The TypeRef APIs are exposed through the stable entrypoint instead of the required experimental aliases, and mutators leave decorator type references pointing to original types.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Experimental TypeRef APIs are exposed through the stable entrypoint, and mixed-template mutation leaves substitutions inconsistent with remapped reference targets.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
The new public Value API and canonical TypeRef storage affect identity guarantees and recursive assignability/mutation across emitters, warranting maintainer architectural review with compiler/emitter integration validation unavailable.
Please keep the general lazy-owner and recursive-cloning mutator fixes in a separate PR for #7003. They affect ordinary type graphs as well as TypeRef, so they should have their own focused regression coverage and review.
The mutator changes here should remain limited to the traversal, canonical storage mapping, and template-substitution consistency required for TypeRef.
Remove generalized serialization recovery and preserve existing example, default, and extension behavior. Keep only native TypeRef integration and consolidate its feature change description.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9d925ae2-0253-4c4d-a87b-49740d9ef737
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Compiler-maintainer review is needed because the new public value variant and cached native storage affect recursive assignability and mutation invariants that could not be exercised in the dependency-free snapshot.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed because findings omitted from the published review identify a critical OpenAPI nullability mismatch and inconsistent TypeRef storage identity.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
typeref(Type)for embedding references to compiler types in metadata values, using native, cachedscalar TypeRef<T = unknown>storage and TypeSpec assignability checks.typerefcompiler feature in the calling project or library. ExportTypeRefType,TypeRefValue, andisTypeRefTypefrom@typespec/compiler; there is no TypeRef-specific experimental subpackage.Opt in
The standard-library function declaration retains a declaration-local
#suppress "experimental-feature"for the separate function-declaration warning. Function use is controlled by thetypereffeature flag.Implementation scope
TypeRefis not a new intrinsic type kind or runtime intrinsic scalar. Its factory resolves the native declaration and uses the compiler's existing instantiation cache. TypeRef-specific assignability remains inareScalarsRelated.Mutation adds direct TypeRef handling while preserving the existing traversal helpers and lazy-clone behavior. Native storage uses the canonical factory; reference values map both their original annotation and precise target. Reference-containing template mappers keep
args,map, andgetMappedTypeconsistent, including mixed type/value arguments.The pre-existing lazy-owner and recursive lazy-clone issues are explicitly outside this PR's scope; this does not claim to fix those graphs. See #7003.
Existing handling of non-representable examples, defaults, and extension values is unchanged. General serialization-error recovery, example filtering, and first-serializable-example selection are outside this PR's scope.
Emitter integration
@operationFieldsresolvers. Ignore operations and metadata models that are not rendered.Related to #6322.
Validation
Full workspace build: 48 successful tasks, followed by engineering checks and compiler signature regeneration. The complete test suite passed: 10,678 tests passed and 25 skipped. Full formatting, format verification, and strict type-aware lint passed. Spelling checks passed for all 39 files in the TypeRef diff.