Describe the bug
Package: @typespec/http-server-csharp 0.58.0-alpha.30
Description
A model property typed as an array of Record<unknown> is emitted as JsonObject[], but the
generated model file does not include using System.Text.Json.Nodes;, so the generated project
fails to compile with CS0246: The type or namespace name 'JsonObject' could not be found.
A property typed as Record<unknown> directly (non-array) works correctly — the using
directive is emitted.
Reproduction
Repro
Playground link
import "@typespec/http";
using Http;
@service(#{ title: "Repro" })
namespace Repro;
model DatasetRow is Record<unknown>;
model Page {
items: DatasetRow[]; // array of Record<unknown> -> JsonObject[]
}
@route("/rows")
interface Rows {
@get list(): Page;
}
Actual output
generated/models/Page.cs (note: no System.Text.Json.Nodes):
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using TypeSpec.Helpers;
using TypeSpec.Helpers.JsonConverters;
namespace Repro
{
public partial class Page
{
[JsonPropertyName("items")]
public required JsonObject[] Items { get; set; } // CS0246
}
}
Expected output
The same file with using System.Text.Json.Nodes; included, as already happens when a property
is typed Record<unknown> without the array.
Root cause
modelNeedsJsonNodes in src/components/models/model-helpers.ts decides whether a model file
gets the System.Text.Json.Nodes using. It checks whether a property's type is a
Record<unknown> model, but never unwraps array types, so Record<unknown>[] (an Array model
whose indexer value is the Record) is missed — while the type-expression emission for the same
property does produce JsonObject[].
Suggested fix
Unwrap array indexers before the record check (loop so nested arrays are covered):
/** Returns true if any property of the model uses Record<T> (mapped to JsonObject). */
export function modelNeedsJsonNodes($: Typekit, model: Model): boolean {
for (const prop of model.properties.values()) {
// Unwrap array types: Record<unknown>[] emits JsonObject[] and needs JsonNodes too
let type = prop.type;
while (type.kind === "Model" && $.array.is(type) && type.indexer?.value) {
type = type.indexer.value;
}
if (type.kind === "Model" && $.record.is(type)) {
// Only need JsonNodes for Record<unknown> (maps to JsonObject)
const valueType = type.indexer?.value;
if (valueType?.kind === "Intrinsic" && valueType.name === "unknown") return true;
}
}
return false;
}
We are running this change as a patch-package patch against the compiled dist output and can
confirm it fixes the compilation error without affecting the existing non-array behavior.
Checklist
Describe the bug
Package:
@typespec/http-server-csharp0.58.0-alpha.30Description
A model property typed as an array of
Record<unknown>is emitted asJsonObject[], but thegenerated model file does not include
using System.Text.Json.Nodes;, so the generated projectfails to compile with
CS0246: The type or namespace name 'JsonObject' could not be found.A property typed as
Record<unknown>directly (non-array) works correctly — the usingdirective is emitted.
Reproduction
Repro
Playground link
Actual output
generated/models/Page.cs(note: noSystem.Text.Json.Nodes):Expected output
The same file with
using System.Text.Json.Nodes;included, as already happens when a propertyis typed
Record<unknown>without the array.Root cause
modelNeedsJsonNodesinsrc/components/models/model-helpers.tsdecides whether a model filegets the
System.Text.Json.Nodesusing. It checks whether a property's type is aRecord<unknown>model, but never unwraps array types, soRecord<unknown>[](an Array modelwhose indexer value is the Record) is missed — while the type-expression emission for the same
property does produce
JsonObject[].Suggested fix
Unwrap array indexers before the record check (loop so nested arrays are covered):
We are running this change as a
patch-packagepatch against the compileddistoutput and canconfirm it fixes the compilation error without affecting the existing non-array behavior.
Checklist