Skip to content

[Optional] attribute for nullable-as-optional opt-in #23

@danfma

Description

@danfma

Current behavior: nullable C# types (`string?`, `int?`, `T?` on a reference type) lower to TypeScript as `T | null` with a default of `null`. This is deliberate — see the `null vs undefined` memo — because APIs crossing the TS boundary benefit from the distinction between "this field is explicitly absent" (null) and "this field was not provided" (undefined).

However, some APIs (React props, JSON bodies that omit absent fields, Hono request schemas) want `undefined` semantics — the `param?: T` form where the key simply isn't set. Today there's no way to opt into that shape.

Goal

Introduce a `[Optional]` attribute that opts a parameter or property into the `param?: T` / `prop?: T` form instead of the default `param: T | null = null`.

Scope

  • `[Optional]` attribute in `Metano.Annotations`
  • Attribute usable on:
    • Method / constructor parameters (flips signature to `name?: T`)
    • Record / class properties (flips field to `name?: T`, no default)
    • Interface properties (`name?: T`)
  • `TypeTransformer` / `InterfaceTransformer` / `RecordClassTransformer` read the attribute and emit the optional form
  • Interaction with nullable types:
    • `string?` + `[Optional]` → `param?: string | null`
    • `string` + `[Optional]` → `param?: string`
  • Tests covering every combination in `tests/Metano.Tests/NullableTranspileTests.cs` (or a new file)
  • Documentation in `docs/attributes.md`

Default still wins

This is opt-in. The default stays `T | null = null` for safety at the API boundary.

Part of #14.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions