Skip to main content

Type Constraints

Type constraint ใน variable ช่วยจับ error ตั้งแต่ตอน plan — ไม่ต้องรอ apply ถึงจะรู้ว่า input ผิด

Primitive Types

variable "name" {
type = string
}

variable "count" {
type = number
}

variable "enabled" {
type = bool
}

Collection Types

list

ลำดับสำคัญ — index ได้

variable "azs" {
type = list(string)
default = ["ap-southeast-1a", "ap-southeast-1b", "ap-southeast-1c"]
}

# Access
locals {
first_az = var.azs[0] # "ap-southeast-1a"
count = length(var.azs) # 3
}

set

ไม่มี order, ไม่มีค่าซ้ำ

variable "users" {
type = set(string)
default = ["alice", "bob", "charlie"]
}

# ใช้กับ for_each
resource "aws_iam_user" "users" {
for_each = var.users
name = each.key
}

map

key-value pair (string keys, value type เดียว)

variable "instance_types" {
type = map(string)
default = {
dev = "t2.micro"
staging = "t2.small"
prod = "t3.large"
}
}

# Access
locals {
current = var.instance_types[var.environment]
}

Structural Types

object

typed key-value (แต่ละ key มี type ต่างกันได้)

variable "database" {
type = object({
name = string
instance_class = string
storage_gb = number
multi_az = bool
tags = map(string)
})

default = {
name = "mydb"
instance_class = "db.t3.micro"
storage_gb = 20
multi_az = false
tags = { Env = "dev" }
}
}

# Access
resource "aws_db_instance" "main" {
identifier = var.database.name
instance_class = var.database.instance_class
allocated_storage = var.database.storage_gb
multi_az = var.database.multi_az
tags = var.database.tags
}

tuple

list ที่แต่ละ position มี type ต่างกัน

variable "record" {
type = tuple([string, number, bool])
default = ["alice", 30, true]
}

# Access
locals {
name = var.record[0] # "alice" (string)
age = var.record[1] # 30 (number)
active = var.record[2] # true (bool)
}

Optional Object Attributes (Terraform 1.3+)

variable "server_config" {
type = object({
name = string
instance_type = string
monitoring = optional(bool, false) # default = false
tags = optional(map(string), {}) # default = {}
})
}

User ไม่ต้องส่ง monitoring / tags — Terraform ใส่ default ให้

any Type

ยอมรับทุก type (อย่าใช้ถ้าไม่จำเป็น)

variable "config" {
type = any
}
ใช้ any เท่าที่จำเป็น
  • any = ไม่มี type checking → bug หาเจอยาก
  • ✅ ใช้ specific type ทุกครั้งที่รู้
  • any ใช้ได้เวลาเขียน module ที่ต้อง flexible จริงๆ

Nested Types

variable "network" {
type = object({
vpc_cidr = string
subnets = list(object({
name = string
cidr_block = string
availability_zone = string
public = bool
}))
})

default = {
vpc_cidr = "10.0.0.0/16"
subnets = [
{ name = "public-1", cidr_block = "10.0.1.0/24", availability_zone = "ap-southeast-1a", public = true },
{ name = "public-2", cidr_block = "10.0.2.0/24", availability_zone = "ap-southeast-1b", public = true },
{ name = "private-1", cidr_block = "10.0.10.0/24", availability_zone = "ap-southeast-1a", public = false },
]
}
}

# ใช้
resource "aws_subnet" "all" {
for_each = { for s in var.network.subnets : s.name => s }

vpc_id = aws_vpc.main.id
cidr_block = each.value.cidr_block
availability_zone = each.value.availability_zone
map_public_ip_on_launch = each.value.public

tags = { Name = each.key }
}

Type Errors

ถ้า input ผิด type → Terraform error ตอน plan:

variable "count" {
type = number
}
$ terraform apply -var="count=abc"
Error: Invalid value for input variable
The given value is not suitable for var.count: a number is required.

Type Conversion

Terraform แปลง type อัตโนมัติเมื่อทำได้:

variable "port" {
type = number
}

# OK — "8080" → 8080
terraform apply -var="port=8080"

หรือใช้ function แปลงเอง:

locals {
port_str = tostring(8080) # "8080"
port_num = tonumber("8080") # 8080
port_set = toset([1, 2, 2, 3]) # [1, 2, 3]
port_list = tolist(toset([1,2,3]))
}

ตัวอย่าง: Module Inputs

modules/vpc/variables.tf
variable "name" {
type = string
description = "VPC name"
}

variable "cidr_block" {
type = string
description = "VPC CIDR block"
default = "10.0.0.0/16"
}

variable "availability_zones" {
type = list(string)
description = "List of AZs"
default = []
}

variable "tags" {
type = map(string)
description = "Tags to apply"
default = {}
}

variable "subnet_config" {
type = object({
public_count = number
private_count = number
nat_gateway = optional(bool, true)
})
description = "Subnet configuration"
}

สรุป

CategoryTypes
Primitivestring, number, bool
Collectionlist(T), set(T), map(T)
Structuralobject({...}), tuple([...])
Specialany, null
Optionaloptional(T, default) (Terraform 1.3+)

Best Practices:

  • ใช้ specific type เสมอ (string ไม่ใช่ any)
  • ใช้ object แทน multiple variables ที่เกี่ยวข้องกัน
  • ใช้ optional() สำหรับ field ที่อาจไม่ได้ส่งมา
  • Nested types ทำให้ config readable แต่อย่าซ้อนเกิน 3 ระดับ

ต่อไป → Variable Definition File