2018-12-11 01:14:33 +01:00
|
|
|
|
---
|
2020-08-15 03:51:06 +02:00
|
|
|
|
layout: "language"
|
2018-12-20 05:34:34 +01:00
|
|
|
|
page_title: "Type Constraints - Configuration Language"
|
2018-12-11 01:14:33 +01:00
|
|
|
|
sidebar_current: "docs-config-types"
|
|
|
|
|
description: |-
|
|
|
|
|
Terraform module authors and provider developers can use detailed type
|
|
|
|
|
constraints to validate the inputs of their modules and resources.
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# Type Constraints
|
|
|
|
|
|
|
|
|
|
Terraform module authors and provider developers can use detailed type
|
|
|
|
|
constraints to validate user-provided values for their input variables and
|
|
|
|
|
resource arguments. This requires some additional knowledge about Terraform's
|
|
|
|
|
type system, but allows you to build a more resilient user interface for your
|
|
|
|
|
modules and resources.
|
|
|
|
|
|
|
|
|
|
## Type Keywords and Constructors
|
|
|
|
|
|
|
|
|
|
Type constraints are expressed using a mixture of _type keywords_ and
|
|
|
|
|
function-like constructs called _type constructors._
|
|
|
|
|
|
|
|
|
|
* Type keywords are unquoted symbols that represent a static type.
|
|
|
|
|
* Type constructors are unquoted symbols followed by a pair of
|
|
|
|
|
parentheses, which contain an argument that specifies more information about
|
|
|
|
|
the type. Without its argument, a type constructor does not fully
|
|
|
|
|
represent a type; instead, it represents a _kind_ of similar types.
|
|
|
|
|
|
|
|
|
|
Type constraints look like other kinds of Terraform
|
2021-01-15 23:13:53 +01:00
|
|
|
|
[expressions](/docs/language/expressions/index.html), but are a special syntax. Within the
|
2018-12-11 01:14:33 +01:00
|
|
|
|
Terraform language, they are only valid in the `type` argument of an
|
2021-01-15 23:13:53 +01:00
|
|
|
|
[input variable](/docs/language/values/variables.html).
|
2018-12-11 01:14:33 +01:00
|
|
|
|
|
|
|
|
|
## Primitive Types
|
|
|
|
|
|
|
|
|
|
A _primitive_ type is a simple type that isn't made from any other types. All
|
|
|
|
|
primitive types in Terraform are represented by a type keyword. The available
|
|
|
|
|
primitive types are:
|
|
|
|
|
|
|
|
|
|
* `string`: a sequence of Unicode characters representing some text, such
|
|
|
|
|
as `"hello"`.
|
|
|
|
|
* `number`: a numeric value. The `number` type can represent both whole
|
|
|
|
|
numbers like `15` and fractional values such as `6.283185`.
|
|
|
|
|
* `bool`: either `true` or `false`. `bool` values can be used in conditional
|
|
|
|
|
logic.
|
|
|
|
|
|
|
|
|
|
### Conversion of Primitive Types
|
|
|
|
|
|
|
|
|
|
The Terraform language will automatically convert `number` and `bool` values
|
|
|
|
|
to `string` values when needed, and vice-versa as long as the string contains
|
|
|
|
|
a valid representation of a number or boolean value.
|
|
|
|
|
|
|
|
|
|
* `true` converts to `"true"`, and vice-versa
|
|
|
|
|
* `false` converts to `"false"`, and vice-versa
|
|
|
|
|
* `15` converts to `"15"`, and vice-versa
|
|
|
|
|
|
|
|
|
|
## Complex Types
|
|
|
|
|
|
|
|
|
|
A _complex_ type is a type that groups multiple values into a single value.
|
|
|
|
|
Complex types are represented by type constructors, but several of them
|
|
|
|
|
also have shorthand keyword versions.
|
|
|
|
|
|
|
|
|
|
There are two categories of complex types: collection types (for grouping
|
|
|
|
|
similar values), and structural types (for grouping potentially dissimilar
|
|
|
|
|
values).
|
|
|
|
|
|
|
|
|
|
### Collection Types
|
|
|
|
|
|
|
|
|
|
A _collection_ type allows multiple values of _one_ other type to be grouped
|
|
|
|
|
together as a single value. The type of value _within_ a collection is called
|
|
|
|
|
its _element type._ All collection types must have an element type, which is
|
|
|
|
|
provided as the argument to their constructor.
|
|
|
|
|
|
|
|
|
|
For example, the type `list(string)` means "list of strings", which is a
|
|
|
|
|
different type than `list(number)`, a list of numbers. All elements of a
|
|
|
|
|
collection must always be of the same type.
|
|
|
|
|
|
|
|
|
|
The three kinds of collection type in the Terraform language are:
|
|
|
|
|
|
|
|
|
|
* `list(...)`: a sequence of values identified by consecutive whole numbers
|
|
|
|
|
starting with zero.
|
|
|
|
|
|
|
|
|
|
The keyword `list` is a shorthand for `list(any)`, which accepts any
|
|
|
|
|
element type as long as every element is the same type. This is for
|
|
|
|
|
compatibility with older configurations; for new code, we recommend using
|
|
|
|
|
the full form.
|
|
|
|
|
* `map(...)`: a collection of values where each is identified by a string label.
|
|
|
|
|
|
|
|
|
|
The keyword `map` is a shorthand for `map(any)`, which accepts any
|
|
|
|
|
element type as long as every element is the same type. This is for
|
|
|
|
|
compatibility with older configurations; for new code, we recommend using
|
|
|
|
|
the full form.
|
2020-04-27 01:52:08 +02:00
|
|
|
|
|
|
|
|
|
Maps can be made with braces ({}) and colons (:) or equals signs (=):
|
|
|
|
|
{ "foo": "bar", "bar": "baz" } OR { foo = "bar", bar = "baz" }. Quotes
|
|
|
|
|
may be omitted on keys, unless the key starts with a number, in which
|
|
|
|
|
case quotes are required. Commas are required between key/value pairs
|
|
|
|
|
for single line maps. A newline between key/value pairs is sufficient
|
|
|
|
|
in multi-line maps.
|
|
|
|
|
|
|
|
|
|
Note: although colons are valid delimiters between keys and values,
|
|
|
|
|
they are currently ignored by `terraform fmt` (whereas `terraform fmt`
|
|
|
|
|
will attempt vertically align equals signs).
|
2018-12-11 01:14:33 +01:00
|
|
|
|
* `set(...)`: a collection of unique values that do not have any secondary
|
|
|
|
|
identifiers or ordering.
|
|
|
|
|
|
|
|
|
|
### Structural Types
|
|
|
|
|
|
|
|
|
|
A _structural_ type allows multiple values of _several distinct types_ to be
|
|
|
|
|
grouped together as a single value. Structural types require a _schema_ as an
|
|
|
|
|
argument, to specify which types are allowed for which elements.
|
|
|
|
|
|
|
|
|
|
The two kinds of structural type in the Terraform language are:
|
|
|
|
|
|
|
|
|
|
* `object(...)`: a collection of named attributes that each have their own type.
|
|
|
|
|
|
|
|
|
|
The schema for object types is `{ <KEY> = <TYPE>, <KEY> = <TYPE>, ... }` — a
|
|
|
|
|
pair of curly braces containing a comma-separated series of `<KEY> = <TYPE>`
|
|
|
|
|
pairs. Values that match the object type must contain _all_ of the specified
|
|
|
|
|
keys, and the value for each key must match its specified type. (Values with
|
|
|
|
|
_additional_ keys can still match an object type, but the extra attributes
|
|
|
|
|
are discarded during type conversion.)
|
|
|
|
|
* `tuple(...)`: a sequence of elements identified by consecutive whole
|
|
|
|
|
numbers starting with zero, where each element has its own type.
|
|
|
|
|
|
|
|
|
|
The schema for tuple types is `[<TYPE>, <TYPE>, ...]` — a pair of square
|
|
|
|
|
brackets containing a comma-separated series of types. Values that match the
|
|
|
|
|
tuple type must have _exactly_ the same number of elements (no more and no
|
|
|
|
|
fewer), and the value in each position must match the specified type for
|
|
|
|
|
that position.
|
|
|
|
|
|
|
|
|
|
For example: an object type of `object({ name=string, age=number })` would match
|
|
|
|
|
a value like the following:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
{
|
|
|
|
|
name = "John"
|
|
|
|
|
age = 52
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Also, an object type of `object({ id=string, cidr_block=string })` would match
|
|
|
|
|
the object produced by a reference to an `aws_vpc` resource, like
|
|
|
|
|
`aws_vpc.example_vpc`; although the resource has additional attributes, they
|
|
|
|
|
would be discarded during type conversion.
|
|
|
|
|
|
|
|
|
|
Finally, a tuple type of `tuple([string, number, bool])` would match a value
|
|
|
|
|
like the following:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
["a", 15, true]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Complex Type Literals
|
|
|
|
|
|
|
|
|
|
The Terraform language has literal expressions for creating tuple and object
|
|
|
|
|
values, which are described in
|
2021-01-15 23:13:53 +01:00
|
|
|
|
[Expressions: Literal Expressions](/docs/language/expressions/types.html#literal-expressions) as
|
2018-12-11 01:14:33 +01:00
|
|
|
|
"list/tuple" literals and "map/object" literals, respectively.
|
|
|
|
|
|
|
|
|
|
Terraform does _not_ provide any way to directly represent lists, maps, or sets.
|
|
|
|
|
However, due to the automatic conversion of complex types (described below), the
|
|
|
|
|
difference between similar complex types is almost never relevant to a normal
|
|
|
|
|
user, and most of the Terraform documentation conflates lists with tuples and
|
|
|
|
|
maps with objects. The distinctions are only useful when restricting input
|
|
|
|
|
values for a module or resource.
|
|
|
|
|
|
|
|
|
|
### Conversion of Complex Types
|
|
|
|
|
|
|
|
|
|
Similar kinds of complex types (list/tuple/set and map/object) can usually be
|
|
|
|
|
used interchangeably within the Terraform language, and most of Terraform's
|
|
|
|
|
documentation glosses over the differences between the kinds of complex type.
|
|
|
|
|
This is due to two conversion behaviors:
|
|
|
|
|
|
|
|
|
|
* Whenever possible, Terraform converts values between similar kinds of complex
|
|
|
|
|
types if the provided value is not the exact type requested. "Similar kinds"
|
|
|
|
|
is defined as follows:
|
|
|
|
|
* Objects and maps are similar.
|
|
|
|
|
* A map (or a larger object) can be converted to an object if it has
|
|
|
|
|
_at least_ the keys required by the object schema. Any additional
|
|
|
|
|
attributes are discarded during conversion, which means map -> object
|
|
|
|
|
-> map conversions can be lossy.
|
|
|
|
|
* Tuples and lists are similar.
|
|
|
|
|
* A list can only be converted to a tuple if it has _exactly_ the
|
|
|
|
|
required number of elements.
|
|
|
|
|
* Sets are _almost_ similar to both tuples and lists:
|
|
|
|
|
* When a list or tuple is converted to a set, duplicate values are
|
|
|
|
|
discarded and the ordering of elements is lost.
|
|
|
|
|
* When a `set` is converted to a list or tuple, the elements will be
|
|
|
|
|
in an arbitrary order. If the set's elements were strings, they will
|
|
|
|
|
be in lexicographical order; sets of other element types do not
|
|
|
|
|
guarantee any particular order of elements.
|
|
|
|
|
* Whenever possible, Terraform converts _element values_ within a complex type,
|
|
|
|
|
either by converting complex-typed elements recursively or as described above
|
|
|
|
|
in [Conversion of Primitive Types](#conversion-of-primitive-types).
|
|
|
|
|
|
|
|
|
|
For example: if a module argument requires a value of type `list(string)` and a
|
|
|
|
|
user provides the tuple `["a", 15, true]`, Terraform will internally transform
|
|
|
|
|
the value to `["a", "15", "true"]` by converting the elements to the required
|
|
|
|
|
`string` element type. Later, if the module uses those elements to set different
|
|
|
|
|
resource arguments that require a string, a number, and a bool (respectively),
|
|
|
|
|
Terraform will automatically convert the second and third strings back to the
|
|
|
|
|
required types at that time, since they contain valid representations of a
|
|
|
|
|
number and a bool.
|
|
|
|
|
|
|
|
|
|
On the other hand, automatic conversion will fail if the provided value
|
|
|
|
|
(including any of its element values) is incompatible with the required type. If
|
|
|
|
|
an argument requires a type of `map(string)` and a user provides the object
|
|
|
|
|
`{name = ["Kristy", "Claudia", "Mary Anne", "Stacey"], age = 12}`, Terraform
|
|
|
|
|
will raise a type mismatch error, since a tuple cannot be converted to a string.
|
2019-06-06 22:28:54 +02:00
|
|
|
|
|
|
|
|
|
## Dynamic Types: The "any" Constraint
|
|
|
|
|
|
|
|
|
|
The keyword `any` is a special construct that serves as a placeholder for a
|
|
|
|
|
type yet to be decided. `any` is not _itself_ a type: when interpreting a
|
|
|
|
|
value against a type constraint containing `any`, Terraform will attempt to
|
|
|
|
|
find a single actual type that could replace the `any` keyword to produce
|
|
|
|
|
a valid result.
|
|
|
|
|
|
|
|
|
|
For example, given the type constraint `list(any)`, Terraform will examine
|
|
|
|
|
the given value and try to choose a replacement for the `any` that would
|
|
|
|
|
make the result valid.
|
|
|
|
|
|
|
|
|
|
If the given value were `["a", "b", "c"]` -- whose physical type is
|
|
|
|
|
`tuple([string, string, string])`, Terraform analyzes this as follows:
|
|
|
|
|
|
|
|
|
|
* Tuple types and list types are _similar_ per the previous section, so the
|
|
|
|
|
tuple-to-list conversion rule applies.
|
|
|
|
|
* All of the elements in the tuple are strings, so the type constraint
|
|
|
|
|
`string` would be valid for all of the list elements.
|
|
|
|
|
* Therefore in this case the `any` argument is replaced with `string`,
|
|
|
|
|
and the final concrete value type is `list(string)`.
|
|
|
|
|
|
|
|
|
|
All of the elements of a collection must have the same type, so conversion
|
|
|
|
|
to `list(any)` requires that all of the given elements must be convertible
|
|
|
|
|
to a common type. This implies some other behaviors that result from the
|
|
|
|
|
conversion rules described in earlier sections.
|
|
|
|
|
|
|
|
|
|
* If the given value were instead `["a", 1, "b"]` then Terraform would still
|
|
|
|
|
select `list(string)`, because of the primitive type conversion rules, and
|
|
|
|
|
the resulting value would be `["a", "1", "b"]` due to the string conversion
|
|
|
|
|
implied by that type constraint.
|
|
|
|
|
* If the given value were instead `["a", [], "b"]` then the value cannot
|
|
|
|
|
conform to the type constraint: there is no single type that both a string
|
|
|
|
|
and an empty tuple can convert to. Terraform would reject this value,
|
|
|
|
|
complaining that all elements must have the same type.
|
|
|
|
|
|
|
|
|
|
Although the above examples use `list(any)`, a similar principle applies to
|
|
|
|
|
`map(any)` and `set(any)`.
|
|
|
|
|
|
|
|
|
|
If you wish to apply absolutely no constraint to the given value, the `any`
|
|
|
|
|
keyword can be used in isolation:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
variable "no_type_constraint" {
|
|
|
|
|
type = any
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In this case, Terraform will replace `any` with the exact type of the given
|
|
|
|
|
value and thus perform no type conversion whatsoever.
|
2020-09-28 02:02:54 +02:00
|
|
|
|
|
|
|
|
|
## Experimental: Optional Object Type Attributes
|
|
|
|
|
|
|
|
|
|
From Terraform v0.14 there is _experimental_ support for marking particular
|
|
|
|
|
attributes as optional in an object type constraint.
|
|
|
|
|
|
|
|
|
|
To mark an attribute as optional, use the additional `optional(...)` modifier
|
|
|
|
|
around its type declaration:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
variable "with_optional_attribute" {
|
|
|
|
|
type = object({
|
|
|
|
|
a = string # a required attribute
|
|
|
|
|
b = optional(string) # an optional attribute
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
By default, for required attributes, Terraform will return an error if the
|
|
|
|
|
source value has no matching attribute. Marking an attribute as optional
|
|
|
|
|
changes the behavior in that situation: Terraform will instead just silently
|
|
|
|
|
insert `null` as the value of the attribute, allowing the recieving module
|
|
|
|
|
to describe an appropriate fallback behavior.
|
|
|
|
|
|
|
|
|
|
Because this feature is currently experimental, it requires an explicit
|
|
|
|
|
opt-in on a per-module basis. To use it, write a `terraform` block with the
|
|
|
|
|
`experiments` argument set as follows:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
terraform {
|
|
|
|
|
experiments = [module_variable_optional_attrs]
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Until the experiment is concluded, the behavior of this feature may see
|
|
|
|
|
breaking changes even in minor releases. We recommend using this feature
|
|
|
|
|
only in prerelease versions of modules as long as it remains experimental.
|