DEV Community

Cover image for user-defined type in Azure Bicep, an introduction
Olivier Miossec
Olivier Miossec

Posted on

user-defined type in Azure Bicep, an introduction

In the Bicep Language, just like in the arm template, variables and parameters have a data type: string, int, array, object, Boolean, secure string, and secure object.
Each datatype has its properties you can use in your bicep files.
But did you know that you can build your datatype?
Creating your own or user-defined datatype has some advantages: better control over parameters and user input, limiting the number of parameters and variables for the same resources, and better-readable code.
Let's dive deep into user-defined data types.
The syntax to create a user-defined type is simple

type nameOfType = Type definition 
Enter fullscreen mode Exit fullscreen mode

You can use decorators to have better control over the use of the custom type.
The type definition is a Bicep expression, it could be as simple as a value, a string or an integer, a complex object with or without optional properties, a reference to an existing type, a union type (a list of allowed values) and you can even use recursion in the expression.

type intType = 10 
param pInt intType 
output out intType = pInt 
Enter fullscreen mode Exit fullscreen mode

Here you have a user-defined type that only
But using a literal value is not very helpful, but a user-define type can be more useful.
In Bicep if you want to control the user input for a parameter to only allow certain values you use the allowed decorator.

 @allowed([
  'Premium_LRS'
  'Premium_ZRS'
  'Standard_LRS'
])
Enter fullscreen mode Exit fullscreen mode

param storageAccountType string
With user-defined type, you can reproduce this by using union type to set the allowed value.

type allowedStorageType = 'Premium_LRS' | 'Premium_ZRS' | 'Standard_LRS'
param storageType allowedStorageType

output out allowedStorageType = storageType
The allowed value for the param storageType is defined in the allowedStorageType and if the value of the parameter storageType is not in the allowed value defined in the user-defined type you get an error.
This is very useful if you need to define several parameters with the same allowed values.
User-defined type is also useful to represent complex objects. Think about a VM, this is a collection of properties, like name, size, os, imagePublisher, and many others.
What if we can put all these properties together instead of several different parameters

type vmConfiguration = {
  OSVersion: '2022-datacenter-azure-edition' | '2022-datacenter-azure-edition-core'
  name: string
  size: 'Standard_D2s_v3' 
  imageOffer: 'WindowsServer'
  imagePublisher: 'MicrosoftWindowsServer'
}
param vmParams vmConfiguration

output out1 string = vmParams.imagePublisher 
output out2 string = vmParams.name 
Enter fullscreen mode Exit fullscreen mode

Here, the OsVersion must be one of the flavors of Windows Datacenter 2022, the vm Name is the only property with any allowed value. To add a control on the size of the string using decorators.

type vmConfiguration = {
  OSVersion: '2022-datacenter-azure-edition' | '2022-datacenter-azure-edition-core'
  @minLength(4)
  @maxLength(15)
  name: string
  size: 'Standard_D2s_v3' 
  imageOffer: 'WindowsServer'
  imagePublisher: 'MicrosoftWindowsServer'
}

param vmParams vmConfiguration

output out1 string = vmParams.imagePublisher 
output out2 string = vmParams.name 
Enter fullscreen mode Exit fullscreen mode

Decorators are valuable in user-defined types.
One of the most useful will be the @export decorator. This decorator is used to indicate that type define in a file could be used in other Bicep files. It is a requirement on large projects where multiple files are used.

Other decorators can be used
@description('’) to add a description to a type or a property
Integer or length control decorators, @minValue(x), @maxValue(x), @minLength(x), @maxLength(x)
@metadata({ }) to add data in a form key/value
And secure type @secure()

User-defined type in Bicep also supports recursion. Recursion is useful if you need to represent hierarchical data or advanced configuration. Recursion in user-defined type is when a type contains a property of its type.

type recursiveObject = {
  stringProperty: string
  recursiveProperty: recursiveObject?
}
Enter fullscreen mode Exit fullscreen mode

The ? in the recursiveProperty indicates that the property recursiveProperty is optional. It is a requirement for recursivity in Bicep.

User-define types in Bicep can add complexity to a Bicep project but it makes the code more readable and easier to manage.

Top comments (0)