This content has been migrated to https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/user-defined-data-types
Bicep 0.12
includes a preview of enhanced parameter type checking. You can enable the preview in your project's bicepconfig.json
file:
{
"experimentalFeaturesEnabled": {
"userDefinedTypes": true
}
}
This feature introduces a new type expression syntax that allows Bicep users to constrain the structure of object
and array
parameters passed into a template and to create reusable type symbols.
Valid type expressions include:
Symbolic references are identifiers that may refer to an "ambient" type (like string
or int
) or a user-defined type symbol declared in a type
statement:
// ambient type reference
type myString = string
// user-defined type reference
type myOtherString = myString
Array types may be declared by suffixing []
to any valid type expression.
param strings string[] = []
param arrayOfArraysOfInts int[][]
Object types contain zero or more properties between curly brackets:
type myObject = {
stringProp: string
recursiveProp?: myObject
}
Properties must have a name on the left-hand side of the colon and a value on the right-hand side. The name may be any string (values that would not be a valid identifier must be enclosed in quotes), and the value may be any type syntax expression. Properties are required unless they have an optionality marker (?
) between the property name and the colon.
Object types may use direct or indirect recursion so long as at least leg of the path to the recursion point is optional. For example, the myObject
definition above is valid (because the directly recursive recursiveProp
property is optional), but the following would not be:
type invalidRecursiveObject = {
level1: {
level2: {
level3: {
level4: {
level5: invalidRecursiveObject
}
}
}
}
}
Because none of level1
, level2
, level3
, level4
, or level5
is optional, there is no JSON object that would be able to fulfill this schema.
Strings, integers, and booleans are all valid types.
type stringLiteral = 'string'
type intLiteral = 10
type boolLiteral = true
Unary operators may be used with integer and boolean literals or references to integer or boolean literal-typed symbols:
type negativeIntLiteral = -10
type negatedIntReference = -negativeIntLiteral
type negatedBoolLiteral = !true
type negatedBoolReference = !negatedBoolLiteral
Unions may include any number of literal-typed expressions. Union types are translated into the allowedValues
constraint in ARM, so only literals are permitted as members.
param oneOfSeveralObjects {foo: 'bar'} | {fizz: 'buzz'} | {snap: 'crackle'}
param mixedTypeArray ('fizz' | 42 | {an: 'object'} | null)[]
Type expressions can be used in four places:
- As the type clause of a
param
statement (i.e., where previously you would specifystring
,int
, etc.), - Following the
=
in atype
statement, - Following the
:
in an object type property, or - Preceding the
[]
in an array type expression.
The user-defined types feature is still under active development, and there are several features that are planned but not yet ready for use.
Like TypeScript tuples, this type would allow users to specify an array of a known, fixed length where each index has its own schema.
type aTuple = [int, string, bool]
Each of the type expressions outlined above is expressed in ARM JSON templates as validation constraints. For example,
param objectParam {
stringProp: string
}
is expressed in ARM as
{
"parameters": {
"objectParam": {
"type": "object",
"required": ["stringProp"],
"properties": {
"stringProp": {
"type": "string"
}
}
}
}
}
ARM does not currently enforce validation constraints on outputs, though this is something we plan to enable.
When dealing with Azure service types, you shouldn't need to redeclare the types a service has already defined. A statement like the following should be permitted in a future release:
param keyVaultNetworkAcls typeof('Microsoft.KeyVault/vaults@2022-07-01').properties.networkAcls