This is unreleased documentation for Flow Developer Portal Next version.
For up-to-date documentation, see the latest version (Current).
Version: Next
Run-time Types
Types can be represented at run-time.
To create a type value, use the constructor function Type<T>(), which accepts the static type as a type argument.
This is similar to e.g. T.self in Swift, T::class/KClass<T> in Kotlin, and T.class/Class<T> in Java.
For example, to represent the type Int at run-time:
let intType: Type = Type<Int>()
This works for both built-in and user-defined types. For example, to get the type value for a resource:
resource Collectible {}
let collectibleType = Type<@Collectible>()
// `collectibleType` has type `Type`
Type values are comparable.
Type<Int>() == Type<Int>()
Type<Int>() != Type<String>()
The method fun isSubtype(of: Type): Bool can be used to compare the run-time types of values.
Run-time types can also be constructed from type identifier strings using built-in constructor functions.
fun CompositeType(_ identifier: String): Type?
fun InterfaceType(_ identifier: String): Type?
fun IntersectionType(types: [String]): Type?
Given a type identifier (or a list of identifiers for interfaces
in the case of IntersectionType), these functions will look up nominal types and
produce their run-time equivalents. If the provided identifiers do not correspond
to any types, or (in the case of IntersectionType) the provided combination of
identifiers would not type-check statically, these functions will produce nil.
struct Test: I {}
struct interface I {}
let type: Type = CompositeType("A.0000000000000001.Test")
// `type` is `Type<Test>`
let type2: Type = IntersectionType(
restrictions: ["A.0000000000000001.I"]
)
// `type2` is `Type<{I}>`
Other built-in functions will construct compound types from other run-types.
fun OptionalType(_ type: Type): Type
fun VariableSizedArrayType(_ type: Type): Type
fun ConstantSizedArrayType(type: Type, size: Int): Type
fun FunctionType(parameters: [Type], return: Type): Type
// returns `nil` if `key` is not valid dictionary key type
fun DictionaryType(key: Type, value: Type): Type?
// returns `nil` if `type` is not a reference type
fun CapabilityType(_ type: Type): Type?
fun ReferenceType(entitlements: [String], type: Type): Type?
The method fun isInstance(_ type: Type): Bool can be used to check if a value has a certain type,
using the concrete run-time type, and considering subtyping rules,
// Declare a variable named `collectible` that has the *static* type `Collectible`
// and has a resource of type `Collectible`
//
let collectible: @Collectible <- create Collectible()
// The resource is an instance of type `Collectible`,
// because the concrete run-time type is `Collectible`
//
collectible.isInstance(Type<@Collectible>()) // is `true`
// The resource is an instance of type `AnyResource`,
// because the concrete run-time type `Collectible` is a subtype of `AnyResource`
//
collectible.isInstance(Type<@AnyResource>()) // is `true`
// The resource is *not* an instance of type `String`,
// because the concrete run-time type `Collectible` is *not* a subtype of `String`
//
collectible.isInstance(Type<String>()) // is `false`
Note that the concrete run-time type of the object is used, not the static type.
// Declare a variable named `something` that has the *static* type `AnyResource`
// and has a resource of type `Collectible`
//
let something: @AnyResource <- create Collectible()
// The resource is an instance of type `Collectible`,
// because the concrete run-time type is `Collectible`
//
something.isInstance(Type<@Collectible>()) // is `true`
// The resource is an instance of type `AnyResource`,
// because the concrete run-time type `Collectible` is a subtype of `AnyResource`
//
something.isInstance(Type<@AnyResource>()) // is `true`
// The resource is *not* an instance of type `String`,
// because the concrete run-time type `Collectible` is *not* a subtype of `String`
//
something.isInstance(Type<String>()) // is `false`
For example, this allows implementing a marketplace sale resource:
access(all) resource SimpleSale {
/// The resource for sale.
/// Once the resource is sold, the field becomes `nil`.
///
access(all) var resourceForSale: @AnyResource?
/// The price that is wanted for the purchase of the resource.
///
access(all) let priceForResource: UFix64
/// The type of currency that is required for the purchase.
///
access(all) let requiredCurrency: Type
access(all) let paymentReceiver: Capability<&{FungibleToken.Receiver}>
/// `paymentReceiver` is the capability that will be borrowed
/// once a valid purchase is made.
/// It is expected to target a resource that allows depositing the paid amount
/// (a vault which has the type in `requiredCurrency`).