Skip to main content
Version: 0.60.1

Structural vs Named Annotations

FScript supports different ways to annotate record-shaped values.

1) Structural annotation

Use {| ... |} when you care about field shape directly.

let formatAddress (address: {| City: string; Zip: int |}) =
$"{address.City} ({address.Zip})"

This means: any value with compatible fields can be used.

2) Named annotation

Use a declared record type name when you want an explicit domain type.

type Project = { Name: string; Version: int }

let describeProject (p: Project) =
$"{p.Name} v{p.Version}"

This is the clearest style when a type is part of your domain model.

3) Declared-type-by-shape annotation

Use { ... } in an annotation to refer to an existing declared record type by its shape.

type Project = { Name: string; Version: int }

let describeProject (p: { Name: string; Version: int }) =
$"{p.Name} v{p.Version}"

This form resolves only when exactly one declared record type matches the shape.

Which one should you use?

  • Prefer named annotation (Project) for public APIs and shared domain types.
  • Use structural annotation ({| ... |}) for local helpers and ad-hoc transforms.
  • Use declared-type-by-shape ({ ... }) only when the shape is unambiguous and intentional.

Practical rule

If the value represents a business/domain concept, define a named record type and annotate with that type name.