Skip to main content

Types

The Types category holds functions for asking, at runtime, what kind of thing a value is, along with a small set of helpers that introspect functions and type descriptors. Each is callable in prefix form fn(x, …) or postfix/UFCS form x fn(…).

Most of these are reflection predicates named is…Type. They overlap with two other type-checking mechanisms documented in Types and Coercion, and it helps to keep the three straight:

  • x is Type (operator) — the idiomatic way to test a value's type, written with a bare type name: 42 is Numbertrue.
  • typeOf(x) (Core) — returns the value's type name as a String, one of the runtime type names ("String", "Number", … "Function" for lambdas).
  • is…Type(x) (this category) — a predicate per type. Unlike the is operator, each is…Type function accepts either a runtime value or a type-name String: isStringType("hello") and isStringType("String") both return true. They also recognize a second tier of descriptor-only labels that aren't real runtime types (see below).

Descriptor-only labels. Six of the predicates — isBinaryType, isUriType, isNamespaceType, isRangeType, isTypeType, isLiteralType (and isFunctionType) — correspond to labels that exist only for reflection. There is no Binary or Uri value in TransformScript (binary data is just a String of bytes), so these predicates only ever return true when handed the matching label String, e.g. isBinaryType("Binary"). The remaining predicates correspond to the real runtime types and answer truthfully for actual values.

Type Predicates (is…Type)

Every predicate takes one argument (:any) and returns a Boolean. The argument may be a live value (isNumberType(42)) or a type-name/label String (isNumberType("Number")).

FunctionSignatureDescriptionExample
isStringType(:any)True for a String value, or the label "String".isStringType("hello")true
isNumberType(:any)True for a Number value, or "Number".isNumberType(42)true
isBooleanType(:any)True for a Boolean value, or "Boolean".isBooleanType(true)true
isNullType(:any)True for null, or the label "Null".isNullType(null)true
isArrayType(:any)True for an Array value, or "Array".isArrayType([1, 2, 3])true
isObjectType(:any)True for an Object value, or "Object".isObjectType({ a: 1 })true
isRegexType(:any)True for a Regex value, or "Regex".isRegexType("Regex")true
isPeriodType(:any)True for a Period value, or "Period".isPeriodType("Period")true
isDateType(:any)True for a Date value, or "Date".isDateType("Date")true
isDateTimeType(:any)True for a DateTime value, or "DateTime".isDateTimeType("DateTime")true
isLocalDateTimeType(:any)True for a LocalDateTime value, or "LocalDateTime".isLocalDateTimeType("LocalDateTime")true
isLocalTimeType(:any)True for a time-of-day value, or "LocalTime".isLocalTimeType("LocalTime")true
isTimeType(:any)True for a time-of-day value, or "Time"/"LocalTime" (the two are aliased).isTimeType("Time")true
isTimeZoneType(:any)True for a TimeZone value, or "TimeZone".isTimeZoneType("TimeZone")true
isFunctionType(:any)True for a lambda/function, or the label "Function".isFunctionType("Function")true
isBinaryType(:any)Descriptor-only: true only for the label "Binary" (no Binary runtime value exists).isBinaryType("Binary")true
isUriType(:any)Descriptor-only: true only for "Uri".isUriType("Uri")true
isNamespaceType(:any)Descriptor-only: true only for "Namespace".isNamespaceType("Namespace")true
isRangeType(:any)Descriptor-only: true only for "Range".isRangeType("Range")true
isTypeType(:any)Descriptor-only: true only for "Type".isTypeType("Type")true
isLiteralType(:any)Descriptor-only: true only for "Literal".isLiteralType("Literal")true

Used as a filter predicate with the $ shorthand:

[1, "a", 2, "b"] filter($ isNumberType())   // → [1, 2]

Examples with temporal values need |…| literals (which contain | and can't sit in a table cell):

isDateType(|2024-01-02|)                  // → true
isDateTimeType(|2020-10-01T23:57:59-07:00|)  // → true
isLocalDateTimeType(|2020-10-01T23:57:59|)   // → true
isLocalTimeType(|23:57:59|)               // → true
isTimeType(|23:57:59|)                     // → true (same underlying value as LocalTime)
isPeriodType(|P1D|)                        // → true

Time / LocalTime aliasing is one-way for labels. A live time value answers true to both isTimeType and isLocalTimeType. For label Strings, isTimeType accepts both "Time" and "LocalTime", but isLocalTimeType("Time")false — it only matches "LocalTime". typeOf(|23:57:59|) is "LocalTime".

Function and Type Introspection

These read structure out of a function value or a function type descriptor. A descriptor is an Object carrying a type (or kind) of "Function" plus paramTypes and returnType keys. Because type is a reserved word in the TransformScript lexer, descriptor Objects must use a quoted key: { "type": "Function", … }.

FunctionSignatureDescriptionExample
functionParamTypes(:any)For a lambda, the list of its parameter names. For a Function descriptor Object, its declared paramTypes array. Raises on a non-function.functionParamTypes((x, y) -> x + y)["x", "y"]
functionReturnType(:any)For a lambda, always "Any" (lambdas carry no declared return type). For a descriptor Object, its declared returnType. Raises on a non-function.functionReturnType((x, y) -> x + y)"Any"

With a descriptor Object (quoted "type" key required):

functionParamTypes({ "type": "Function", "paramTypes": ["String", "Number"], "returnType": "Boolean" })
// → ["String", "Number"]

functionReturnType({ "type": "Function", "paramTypes": ["String"], "returnType": "Boolean" })
// → "Boolean"

functionParamTypes on a lambda returns parameter names, not their types — lambdas are untyped, so the names are all that's known. Passing a non-function (e.g. functionParamTypes("hello")) raises Expected Function type, got String.

typePredicate is not callable on its own. It is the base for the is…Type predicates and has no type of its own to test. Use the concrete is…Type predicates instead.