Bicep 中的用户定义的数据类型

了解如何在 Bicep 中创建用户定义的数据类型。 有关系统定义的数据类型,请参阅数据类型

需要安装 Bicep CLI 0.12.X 或更高版本才能使用此功能。

定义类型

可以使用 type 语句来创建用户定义的数据类型。 此外,还可以在某些位置使用类型表达式来定义自定义类型。

@<decorator>(<argument>)
type <user-defined-data-type-name> = <type-expression>

@allowed 修饰器仅在 param 语句上受允许。 若要在 type 中声明具有一组预定义值的类型,请使用联合类型语法

有效的类型表达式包括:

  • 符号引用是引用环境类型(如 stringint)或引用在 type 语句中声明的用户定义类型符号的标识符:

    // Bicep data type reference
    type myStringType = string
    
    // user-defined type reference
    type myOtherStringType = myStringType
    
  • 原始字面量,包括字符串、整数和布尔值,都是有效的类型表达式。 例如:

    // a string type with three allowed values.
    type myStringLiteralType = 'bicep' | 'arm' | 'azure'
    
    // an integer type with one allowed value
    type myIntLiteralType = 10
    
    // an boolean type with one allowed value
    type myBoolLiteralType = true
    
  • 可以通过将 [] 附加到任何有效的类型表达式来声明数组类型:

    // A string type array
    type myStrStringsType1 = string[]
    // A string type array with three allowed values
    type myStrStringsType2 = ('a' | 'b' | 'c')[]
    
    type myIntArrayOfArraysType = int[][]
    
    // A mixed-type array with four allowed values
    type myMixedTypeArrayType = ('fizz' | 42 | {an: 'object'} | null)[]
    
  • 对象类型在大括号之间包含零个或多个属性:

    type storageAccountConfigType = {
      name: string
      sku: string
    }
    

    对象中的每个属性都包含一个键和一个值,用冒号 : 分隔。 键可以是任何字符串,将非标识符值放在引号中,值可以是任何类型的表达式。

    除非在属性值后面具有可选的标记 ?,否则属性是必需的。 例如,以下示例中的 sku 属性是可选的:

    type storageAccountConfigType = {
      name: string
      sku: string?
    }
    

    修饰器可用于属性。 * 可用于使所有值都需要一个常数。 使用 * 时,仍可以定义其他属性。 此示例会创建一个对象,该对象需要一个名为 idint 类型的键,并且对象中的所有其他条目必须是长度至少为 10 个字符的字符串值。

    type obj = {
      @description('The object ID')
      id: int
    
      @description('Additional properties')
      @minLength(10)
      *: string
    }
    

    以下示例演示如何使用联合类型语法列出一组预定义值:

    type directions = 'east' | 'south' | 'west' | 'north'
    
    type obj = {
      level: 'bronze' | 'silver' | 'gold'
    }
    

    递归

    对象类型可以使用直接或间接递归,前提是递归点的路径至少有一段是可选的。 例如,以下示例中的 myObjectType 定义是有效的,因为直接递归 recursiveProp 属性是可选的:

    type myObjectType = {
      stringProp: string
      recursiveProp: myObjectType?
    }
    

    但是,以下类型定义无效,因为 level1level2level3level4level5 都不是可选的。

    type invalidRecursiveObjectType = {
      level1: {
        level2: {
          level3: {
            level4: {
              level5: invalidRecursiveObjectType
            }
          }
        }
      }
    }
    
  • Bicep 一元运算符可结合整数和布尔字面量使用,或结合对整数或布尔字面量类型的符号的引用:

    type negativeIntLiteral = -10
    type negatedIntReference = -negativeIntLiteral
    
    type negatedBoolLiteral = !true
    type negatedBoolReference = !negatedBoolLiteral
    
  • 联合可以包含任意数量的字面量类型表达式。 联合类型在 Bicep 中被翻译为允许值约束,因此只有字面量可以作为成员。

    type oneOfSeveralObjects = {foo: 'bar'} | {fizz: 'buzz'} | {snap: 'crackle'}
    type mixedTypeArray = ('fizz' | 42 | {an: 'object'} | null)[]
    

除了用于 type 语句之外,类型表达式还可用于以下位置,以创建用户定义的数据类型:

  • 作为 param 语句的类型子句。 例如:

    param storageAccountConfig {
      name: string
      sku: string
    }
    
  • 在对象类型属性中的 : 之后。 例如:

    param storageAccountConfig {
     name: string
      properties: {
        sku: string
      }
    } = {
      name: 'store$(uniqueString(resourceGroup().id)))'
      properties: {
        sku: 'Standard_LRS'
      }
    }
    
  • 在数组类型表达式中的 [] 之前。 例如:

    param mixedTypeArray ('fizz' | 42 | {an: 'object'} | null)[]
    

用于创建存储帐户的典型 Bicep 文件如下所示:

param location string = resourceGroup().location
param storageAccountName string

@allowed([
  'Standard_LRS'
  'Standard_GRS'
])
param storageAccountSKU string = 'Standard_LRS'

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: storageAccountSKU
  }
  kind: 'StorageV2'
}

通过使用用户定义的数据类型,它可以如下所示:

param location string = resourceGroup().location

type storageAccountSkuType = 'Standard_LRS' | 'Standard_GRS'

type storageAccountConfigType = {
  name: string
  sku: storageAccountSkuType
}

param storageAccountConfig storageAccountConfigType

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' = {
  name: storageAccountConfig.name
  location: location
  sku: {
    name: storageAccountConfig.sku
  }
  kind: 'StorageV2'
}

使用修饰器

修饰器是以 @expression 格式编写的,放置在用户定义的数据类型的声明上方。 下表显示了用户定义的数据类型的可用修饰器。

修饰器 应用于 参数 说明
说明 all string 提供用户定义数据类型的说明。
鉴别器 object string 使用此修饰器来确保标识和管理正确的子类。
export 全部 指示用户定义的数据类型可供另一个 Bicep 文件导入。
maxLength 数组、字符串 int 字符串和数组数据类型的最大长度。 最大值包含在内。
maxValue int int 整数数据类型的最大值。 最大值包含在内。
metadata all object 要应用于数据类型的自定义属性。 可以包含与说明修饰器等效的说明属性。
minLength 数组、字符串 int 字符串和数组数据类型的最小长度。 最小值包含在内。
minValue int int 整数数据类型的最小值。 最小值包含在内。
sealed object 如果 use-define 数据类型的属性名称可能存在拼写错误,则将 BCP089 从警告提升为错误。 有关详细信息,请参阅提升错误级别
secure 字符串、对象 将这些类型标记为安全。 安全类型的值不会保存到部署历史记录中,也不会记录在日志中。 有关详细信息,请参阅保护字符串和对象

修饰器位于 sys 命名空间中。 如果需要将修饰器与具有相同名称的其他项区分开来,请在修饰器前面加上 sys。 例如,如果 Bicep 文件包含名为 description 的变量,则必须在使用说明修饰器时添加 sys 命名空间

鉴别器

请参阅标记的联合数据类型

说明

为用户定义的数据类型添加说明。 修饰器可用于属性。 例如:

@description('Define a new object type.')
type obj = {
  @description('The object ID')
  id: int

  @description('Additional properties')
  @minLength(10)
  *: string
}

Markdown 格式的文本可用于说明文本。

导出

使用 @export() 来与其他 Bicep 文件共享用户定义的数据类型。 有关详细信息,请参阅导出变量、类型和函数

整数约束

你可以设置整数类型的最小值和最大值。 可以设置一个或两个约束。

@minValue(1)
@maxValue(12)
type month int

长度约束

你可以指定字符串和数组类型的最小和最大长度。 可以设置一个或两个约束。 对于字符串,长度指示字符数。 对于数组,长度指示数组中的项数。

以下示例声明了两种类型。 一种类型对应于必须具有 3-24 个字符的存储帐户名称。 另一种类型是必须具有 1-5 个项的数组。

@minLength(3)
@maxLength(24)
type storageAccountName string

@minLength(1)
@maxLength(5)
type appNames array

元数据

如果你有要应用于用户定义的数据类型的自定义属性,请添加元数据修饰器。 在元数据中,使用自定义名称和值来定义对象。 为元数据定义的对象可以包含任何名称和类型的属性。

你可以使用此修饰器来跟踪不适合添加到描述中的数据类型相关信息。

@description('Configuration values that are applied when the application starts.')
@metadata({
  source: 'database'
  contact: 'Web team'
})
type settings object

当向 @metadata() 修饰器提供与另一个修饰器冲突的属性时,该修饰器始终优先于 @metadata() 修饰器中的任何内容。 因此,@metadata() 值中的冲突属性是冗余的,将被替换。 有关详细信息,请参阅无冲突元数据

已密封

请参阅提升错误级别

安全类型

你可以将用户定义的字符串或对象数据类型标记为安全类型。 安全类型的值不会保存到部署历史记录中,也不会记录在日志中。

@secure()
type demoPassword string

@secure()
type demoSecretObject object

提升错误级别

默认情况下,在 Bicep 中声明对象类型允许它接受任何类型的附加属性。 例如,以下 Bicep 有效,但会引发 [BCP089] 警告 - The property "otionalProperty" is not allowed on objects of type "{ property: string, optionalProperty: null | string }". Did you mean "optionalProperty"?

type anObject = {
  property: string
  optionalProperty: string?
}
 
param aParameter anObject = {
  property: 'value'
  otionalProperty: 'value'
}

该警告表明 anObject 类型不包含名为 otionalProperty 的属性。 虽然部署期间没有发生任何错误,但 Bicep 编译器认为 otionalProperty 是拼写错误,你本想使用 optionalProperty,但拼写错误,并提醒你注意不一致之处。

若要将这些警告升级为错误,请将 @sealed() 修饰器应用于对象类型:

@sealed() 
type anObject = {
  property: string
  optionalProperty?: string
}

通过将 @sealed() 装饰器应用于 param 声明,可以获得相同的结果:

type anObject = {
  property: string
  optionalProperty: string?
}
 
@sealed() 
param aParameter anObject = {
  property: 'value'
  otionalProperty: 'value'
}

ARM 部署引擎还会检查密封类型是否有其他属性。 为密封参数提供任何额外属性都会导致验证错误,从而导致部署失败。 例如:

@sealed()
type anObject = {
  property: string
}

param aParameter anObject = {
  property: 'value'
  optionalProperty: 'value'
}

标记的联合数据类型

若要在 Bicep 文件中声明自定义标记联合数据类型,可以在用户定义的类型声明上方放置 discriminator 修饰器。 需要安装 Bicep CLI 0.21.X 或更高版本才能使用此修饰器。 以下示例演示如何声明标记的联合数据类型:

type FooConfig = {
  type: 'foo'
  value: int
}

type BarConfig = {
  type: 'bar'
  value: bool
}

@discriminator('type')
type ServiceConfig = FooConfig | BarConfig | { type: 'baz', *: string }

param serviceConfig ServiceConfig = { type: 'bar', value: true }

output config object = serviceConfig

有关详细信息,请参阅自定义标记的联合数据类型

后续步骤

  • 有关 Bicep 数据类型的列表,请参阅数据类型