Static typing
FQL supports static typing of queries and user-defined functions. Static typing identifies potential query errors before execution by validating the query shape before running the query to rule out runtime errors.
FQL verifies that the query is correct for the kinds of values that it can accept and runs the query after type checking passes. Types are inferred by usage. After a type is determined, usage must be consistent.
Types
A type is the type of a signature value and can be any of the following:
Type | Description | Syntax | Examples |
---|---|---|---|
named |
name |
See a partial list of named types. |
|
literal |
A literal value has its own type. For example, |
literal value |
|
function |
A function type doesn’t have a name. It has a list of arguments and a
return type. For example, the function |
(arg_name: arg_type) => return_type |
|
union |
A union represents an OR between any number of types. For example, if a
function accepts an integer or a string, it accepts the type |
type1 | type2 | type3 |
|
intersection |
An intersection represents an AND between any number of types, combining
multiple types into a single type. For example, the types |
type1 & type2 & type3 |
|
The following is a partial list of named types.
Type | Example value | Notes |
---|---|---|
|
||
|
||
|
||
|
||
|
||
|
||
Array<A> |
|
The type parameter |
Set<A> |
|
The type parameter |
|
||
|
Generic types
A type can be a concrete or generic type.
A generic type is a type that has type parameters. A type parameter is
similar to a named type but isn’t known in a function signature and is,
effectively, a placeholder type. The type parameter signature is a single
capital letter in sequence, such as A
, B
, and C
.
These types resolve to a concrete type after the value is used. For
example, the elements in an Array have the type A
in signatures because an
array can store any type. The type parameter A
resolves to a concrete type
after the Array is constructed.
Signatures
A signature is the definition of a field or function in the static environment.
FQL method signatures are a simplified form of TypeScript and can be in one of the two following formats:
-
Function signatures have the form name(arg_name: arg_type) => return_type. For example, concat has the signature
concat(other: String) => String
. Function signatures are similar to function types, but include a name on the left. -
Field signatures have the form name: type. For example, the field year on Date has the signature
year: Int
.
Type parameters act like placeholders in a signature. This means that
Array<A>
isn’t a static type because it has a type parameter. When you
construct an Array, for example, with the query [1, 2]
, the concrete type of
that Array is Array<1 | 2>
, because the value of the Array is determined to
have the type 1 | 2
.
The type parameter A
is then substituted on calling functions on that
array. For example, the function first()
on an Array has the signature
first() => A | Null
. This means that it returns a value that is the same
type as the elements of the Array, A
, or a null value.
After first()
is called, for example, in [1, 2].first()
, the type A
is
resolved. In this case, first()
has the concrete type () => 1 | 2 | Null
because the type A
resolves to 1 | 2
.
Type parameters on functions are defined implicitly, in
alphabetical order. For example, dbg()
accepts a value and returns that
same value. So, the signature is dbg(value: A) => A
. The type parameter A
is local to the dbg()
function and is defined implicitly.
The dbg()
function is called a generic function because it has type
parameters.
Generic type signature
For types that include parameters, new type parameters start at B
,
followed by C
, and continue. For example, concat()
on Arrays has the
signature concat(other: Array<B>) => Array<A | B>
. The type parameter A
is
the type of the Array this is called on, and the type parameter B
is a new
type parameter local to this function.
The type Array
is a generic type because it has type parameters.
Enable and disable type checking
Scope | Property | Description |
---|---|---|
Database |
typechecked |
Enable or disable type checking for the database: |
Query |
typecheck |
Enable or disable type checking per query: |
If type checking is enabled for the driver or per query, type checking must also be enabled in the database.
Setting the typechecked property in the driver, query, or Dashboard overrides the database setting.
Type checking is performed on user-defined function (UDF) definitions and
can’t be disabled. If a UDF definition fails type checking it results in a
QueryRuntimeError
. This differs from the compile-time TypeCheckError
returned by a query type error.
Disabling type checking can reduce the query time, and the number of query check phase compute operations but can allow errors to present as runtime errors.
Enable database type checking
Enabled type checking for a child database by updating the database
definition using the
document.update()
method:
Database.byName( "childDB" )!.update( { typechecked: true } )
Enable query type checking
Drivers for the supported languages can be configured to enable type checking at two levels:
-
Enable type checking of all queries sent by the driver by setting the
typecheck
property totrue
in the driver client configuration. -
Enable type checking per-query by setting the
typecheck
property totrue
in the query options field.
Is this article helpful?
Tell Fauna how the article can be improved:
Visit Fauna's forums
or email docs@fauna.com
Thank you for your feedback!