Skip to content

Scalars

A scalar is a single value: a string, a number, a boolean, a moment in time. A model has properties; a scalar does not.

Every TypeSpec scalar maps to a JSON Schema type. Where JSON Schema also has a format for the finer kind, such as int32 or date-time, that is written too.

A named scalar behaves like a named model: it becomes an entry in components.schemas, and every use site points at it with $ref.

Built-in scalars

TypeSpectypeformat
stringstring
booleanboolean
integerinteger— (abstract, width unspecified)
numeric, floatnumber— (abstract, width unspecified)
int8 / int16 / int32 / int64integerint8 / int16 / int32 / int64
safeintintegerint64
uint8 / uint16 / uint32 / uint64integeruint8 / uint16 / uint32 / uint64
float32numberfloat
float64numberdouble
decimalnumberdecimal
decimal128numberdecimal128
bytesstringbyte
plainDatestringdate
plainTimestringtime
utcDateTime, offsetDateTimestringdate-time
durationstringduration
urlstringuri

Intrinsic types:

TypeSpecOutputMeaning
null{ type: "null" }
never, void{ not: {} }No value is valid
unknown{}Any value is valid

User-declared scalars

extends derives a new scalar from an existing one. The shape comes from the base, and the new scalar adds its own documentation and validation keywords. The rules live on the scalar, so every field that uses it carries them:

typespec
@doc("An RFC 5321 mailbox address.")
@maxLength(254)
scalar Email extends string;

model Account {
  email: Email;
}
yaml
components:
  schemas:
    Email:
      type: string
      description: An RFC 5321 mailbox address.
      maxLength: 254
    Account:
      type: object
      properties:
        email:
          $ref: "#/components/schemas/Email"
      required:
        - email

If a property re-declares a keyword its scalar already carries (say, @minLength(2) on a property whose scalar has @minLength(5)), the property does not override the scalar. The two constraints are combined with allOf, so both hold.

TIP

This is where a scalar earns its keep for a business concept. Something like Email, OrderId or Percentage turns up all over a system. Write the rule on the scalar once and every field that uses it carries the same constraint, with nothing to annotate field by field and nothing for anyone to forget. Changing the rule is one edit.