microsoft / microsoft/typespec
[Bug]: [http-server-csharp] Model with a `Record<unknown>[]` property generates C# that does not compile (missing `using System.Text.Json.Nodes;`)
- Dominant language
- Java
- Stars
- 5.9k
- Forks
- 394
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 104
Description
### Describe the bug
**Package**: `@typespec/http-server-csharp` `0.58.0-alpha.30`
## Description
A model property typed as an **array of** `Record` 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` *directly* (non-array) works correctly — the using
directive is emitted.
### Reproduction
## Repro
[Playground link](https://typespec.io/playground/?tspconfig=ZW1pdDoKICAtICJAdHlwZXNwZWMvaHR0cC1zZXJ2ZXItY3NoYXJwIgo%3D&c=aW1wb3J0ICJAdHlwZXNwZWMvaHR0cCI7DQp1c2luZyBIdHRwOw0KDQpAc2VydmljZSgjeyB0aXRsZTogIlJlcHJvIiB9KQ0KbmFtZXNwYWNlIMUVxTNtb2RlbCBEYXRhc2V0Um93IGlzIFJlY29yZDx1bmtub3duPssoUGFnZSB7DQogIGl0ZW1zOss5W107IC8vIGFycmF5IG9m0EUgLT4gSnNvbk9iamVjdFtdDQp9xFdAcm91dGUoIi9yb3dzIikNCmludGVyZuUApG93c8ZsQGdldCBsaXN0KCk65QCDO8U%2B&vs=%7B%7D)
```typespec
import "@typespec/http";
using Http;
@service(#{ title: "Repro" })
namespace Repro;
model DatasetRow is Record;
model Page {
items: DatasetRow[]; // array of Record -> JsonObject[]
}
@route("/rows")
interface Rows {
@get list(): Page;
}
```
## Actual output
`generated/models/Page.cs` (note: no `System.Text.Json.Nodes`):
```csharp
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` 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` model, but never unwraps array types, so `Record[]` (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):
```ts
/** Returns true if any property of the model uses Record (mapped to JsonObject). */
export function modelNeedsJsonNodes($: Typekit, model: Model): boolean {
for (const prop of model.properties.values()) {
// Unwrap array types: Record[] 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 (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
- [x] Follow our [Code of Conduct](https://github.com/microsoft/typespec/blob/main/CODE_OF_CONDUCT.md)
- [x] Check that there isn't already an issue that request the same bug to avoid creating a duplicate.
- [x] Check that this is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/Microsoft/typespec/discussions).
- [x] The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.
Contributor guide
Research direction
Start in src/components/models/model-helpers.ts at modelNeedsJsonNodes and inspect how array model indexers are handled before the Record check. Reproduce the issue with the linked Playground example, then verify that generated/models/Page.cs includes System.Text.Json.Nodes and that the generated project compiles without changing direct Record behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, typescript
- Domain
- backend, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100