Types and Coercion
Files TransformScript has a small set of runtime value types and several distinct ways of converting between them. The conversion mechanisms deliberately differ from one another, so knowing which one applies in a given spot is the key to predicting what your script returns.
Runtime Types
These are the real values a script manipulates. Each can be tested with is, produced by typeOf, and, where it makes sense, targeted with as.
| Type | What It Is | Literal Example |
|---|---|---|
String | text | "abc" |
Number | integer or decimal | 42, 42.5 |
Boolean | true / false | true |
Null | absence of a value | null |
Array | ordered list | [1, 2, 3] |
Object | key/value map | { a: 1 } |
Regex | regular expression | /foo/i |
Date | calendar date, no time | |2024-05-01| |
DateTime | zoned instant | |2020-10-01T23:57:59-07:00| |
LocalDateTime | date + time, no zone | |2020-10-01T23:57:59| |
LocalTime / Time | time of day | |23:57:59| |
Period | ISO-8601 duration | |P1D|, |PT3H| |
TimeZone | a time zone | (no literal; via coercion) |
typeOf(x) returns one of these names. LocalTime and Time are the same underlying type, aliased to each other. Functions are reflectable, so typeOf(aLambda) is "Function", but Function is not a value you can write as a literal or coerce to.
Binary and Uri are not standalone value types. Binary data is just a String of bytes, so there is nothing to construct or cast to: x as Binary and x as Uri raise an error.
Temporal Types
The temporal types are first-class values, not strings.
Date is a calendar date. LocalTime is a wall-clock time with hour, minute, second, and optional fractional seconds. LocalDateTime pairs a Date and a LocalTime with no zone. DateTime is a zoned instant.
Period is an ISO-8601 duration with fields for years, months, weeks, days, hours, minutes, and seconds. Periods add and subtract field-wise, so |P1D| + |PT3H| gives |P1DT3H|, and they apply to temporals, so |2021-03-02T10:39:59| - |P1D| gives |2021-03-01T10:39:59|. Applying time-of-day components to a bare Date raises an error, because a Date has no time to adjust.
Coercion: Four Mechanisms
TransformScript coerces values in four different places, and they do not all agree. Each is described separately because the differences matter.
Truthiness in Conditionals and Filters
When a value is used as a condition, such as in a ternary, an if, a filter selector, or an if-guarded object entry, it is tested for truthiness. The rule is strict about strings: a string is truthy only if it equals "true" (case-insensitive, trimmed). So "yes", "0", and "1" are all falsy; only "true" is truthy. Numbers are truthy when non-zero. null and false are falsy. Everything else is truthy.
The boolean operators and, or, and not are stricter still. They require actual booleans and raise an error on anything else.
Explicit Cast With as Type
expr as Type { options } converts using the target type's rules. If the value already matches and you give no options, it passes through unchanged.
42 as Stringgives"42"."42" as Numbergives42, an integer, with the integer type preserved."false" as Booleangivesfalse.as Numberparses integer-looking strings to integers, supports locale separators (decimalSeparator,groupingSeparator,locale), and raises an error on empty input.as Booleanacceptstrue/t/yes/y/1andfalse/f/no/n/0/null/"", and raises an error on anything else. You can customize the accepted values withtrueValuesandfalseValues.as Stringkeepsnullasnull, formats temporals (honoring aformatstrftime string andtimeZone), and JSON-encodes arrays and objects.- Temporal casts accept a
format(strptime) and convert among temporal types.Number as DateTimetreats the number as epoch seconds.
Unknown option keys, or casting to a type that is not a runtime type, raise an error.
Conversion Functions Such as toString and toNumber
The toX functions are separate from as Type and differ in their edge cases.
toString(null)gives"", whereasnull as Stringgivesnull.toNumber(x)always returns a decimal, sotoNumber("42")gives42.0, unlikeas Number, which preserves integers.toBoolean(x)never raises an error. It accepts1/yes/0/noand falls back to truthiness, unlikeas Boolean, which raises on unrecognized strings.toDecimal,toBinary(which produces aStringof bytes), and the temporaltoDate,toDateTime,toLocalDateTime, andtoTimeround out the set.
Implicit Coercion in Operators
Arithmetic operators coerce operands to numbers: a numeric string becomes a number, true becomes 1, false and null become 0, and a non-numeric string raises an error. The notable overload is +. If either side is a string, the result is string concatenation, so 1 + "a" gives "1a". For arrays, + concatenates or pushes. The strict ++, <<, and >> operators require matching operand types.
Equality and Ordering
== and != are strict and do no coercion. A text-only object compares equal to the equivalent plain string.
~= is coercive equality. It coerces one operand toward the other's shape and then compares, so "true" ~= true is true and "1" ~= 2 is false. It coerces recursively through arrays and objects.
The relational operators >, >=, <, and <= are left-type-driven. They return false if either operand is null. Otherwise they coerce the right operand to the left operand's type and compare. If the right side cannot be coerced to match, the result is false.