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

了解如何在 Bicep 中创建用户定义的数据类型。 有关系统定义的数据类型,请参阅数据类型。 使用用户定义的数据类型时会自动启用语言版本 2.0 代码生成。

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

use-user-defined-types linter 规则鼓励使用用户定义的数据类型,而不是泛型object或array类型。

定义类型

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

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

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

有效的类型表达式包括:

符号引用

符号引用是用于引用 ambient 类型(如 string 或 int)或在 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)[]

联合类型

联合类型允许创建由一组子类型组成的组合类型。 如果值与任一子类型匹配,则该值与类型匹配。 使用管道 (|) 运算符分隔各个成员类型。 Bicep将联合类型转换为允许值约束,因此仅允许文本作为成员。 联合可以包含任意数量的字面量类型表达式。

type directions = 'east' | 'south' | 'west' | 'north'

type obj = {
  level: 'bronze' | 'silver' | 'gold'
}

可以内联声明联合类型,成员可以是对另一个文本类型符号的引用。

混合类型联合

成员类型不需要是相同的文本类型。 联合类型可以组合字符串、整数、布尔值、对象和 null 字面量。

type mixedType = 'fizz' | 42 | { an: 'object' } | null

Note

此 | 运算符还用于本文其他地方所述的多个相关方案:

  • 若要创建其元素受联合成员约束的数组,请参阅 数组类型。
  • 若要将 | 运算符与 @discriminator() 修饰器配对并生成区分的联合,请参阅 “标记联合”数据类型。
  • 当您使用 资源派生类型 时,它们展开后的等效形式会表示为联合类型。

对象类型

对象类型在大括号之间包含零个或多个属性:

type storageAccountConfigType = {
  name: string
  sku: string
}

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

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

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

可以在属性上使用修饰器。 可以使用星号 (*) 让所有值都需要约束。 使用 * 可以定义更多属性。 此示例创建的对象需要一个名为 int 的 id 类型的键。 对象中的所有其他条目都必须是长度至少为 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?
}

以下类型定义无效,因为 level1、level2、level3、level4 和 level5 都不是可选的。

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@2025-06-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@2025-06-01' = {
  name: storageAccountConfig.name
  location: location
  sku: {
    name: storageAccountConfig.sku
  }
  kind: 'StorageV2'
}

使用修饰器

以格式 @expression 编写修饰器,并将其置于用户定义的数据类型的声明之上。 下表显示了用户定义的数据类型的可用修饰器。

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

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

鉴别器

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

说明

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

@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 个字符的存储帐户名称。 另一种类型是必须具有一至五个项的数组。

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

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

元数据

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

使用此修饰器来记录不适合添加到 description 中的有关数据类型的信息。

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

当你为修饰器提供与另一个 @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 但出现了拼写错误。 Bicep 会提醒你存在不一致。

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

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

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

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

Azure 资源管理器部署引擎还会检查密封类型的其他属性。 为密封参数提供任何额外属性都会导致验证错误,而这些错误会导致部署失败。 例如:

@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使你能够使用resourceInput<>和resourceOutput<>构造直接从Azure资源架构派生类型。 通过使用资源派生类型,可以针对资源主体的一部分(而不是使用自定义类型)检查参数和变量。 若要使用这些构造,需要Bicep CLI 0.34.1 或更高版本。

模板可以在需要特定类型的地方重复使用资源类型。

resourceInput<'type@version'>
  • resourceInput<>:表示资源类型的可写属性,删除 ARM 模板架构中标记为 ReadOnly 的任何属性。 它使用需要传递给资源声明的类型。
resourceOutput<'type@version'>

resourceOutput<>:表示资源类型的可读属性,去除 ARM 模板架构中标记为 WriteOnly 的任何属性。 它与预配资源后返回的值的类型匹配。

  • resourceOutput<>:表示资源类型的可读属性,删除 ARM 模板架构中标记为 WriteOnly 的任何属性。 它与预配资源后返回的值的类型匹配。
type accountKind = resourceInput<'Microsoft.Storage/storageAccounts@2024-01-01'>.kind

前面的示例等效于:

type accountKind = 'BlobStorage' | 'BlockBlobStorage' | 'FileStorage' | 'Storage' | 'StorageV2'

以下示例演示如何根据 resourceInput<> 存储帐户资源创建类型化参数 properties 。 此方法定义一个参数,该参数与存储帐户的可写属性(例如 accessTier, minimumTlsVersion和其他属性)匹配:

// Typed parameter using the .properties path of a storage account
param storageAccountProps resourceInput<'Microsoft.Storage/storageAccounts@2023-01-01'>.properties = {
  accessTier: 'Hot'
  minimumTlsVersion: 'TLS1_2'
  allowBlobPublicAccess: false
  supportsHttpsTrafficOnly: true
}

// Resource declaration using the typed parameter
resource storageAccount 'Microsoft.Storage/storageAccounts@2025-06-01' = {
  name: 'mystorageacct123'
  location: resourceGroup().location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: storageAccountProps
}

以下示例演示如何使用 resourceOutput<> 根据存储帐户资源的 primaryEndPoints 创建类型化输出。

output storageEndpoints resourceOutput<'Microsoft.Storage/storageAccounts@2024-01-01'>.properties.primaryEndpoints = ...

与用户定义的数据类型不同,Bicep在编辑或编译文件时检查资源派生的类型,但 ARM 服务不会检查它们。

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