你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

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

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

需要安装 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 格式编写的,放置在用户定义的数据类型的声明上方。 下表显示了用户定义的数据类型的可用修饰器。

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

修饰器位于 sys 命名空间中。 如果需要将修饰器与具有相同名称的其他项区分开来,请在修饰器前面加上 sys。 例如,如果 Bicep 文件包含名为 description 的变量,则必须在使用 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 个字符的存储帐户名称。 另一种类型是必须有一到五个项的数组。

@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,但拼写错误了。 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 的任何属性。 它与预配资源后返回的值的类型匹配。

可以应用 resourceInput<>resourceOutput<> 仅提取资源架构的一部分。 例如,根据存储帐户的 kindproperties 键入变量或参数:

type accountKind = resourceInput<'Microsoft.Storage/storageAccounts@2024-01-01'>.kind

前面的示例等效于:

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

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

// 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@2023-01-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 数据类型的列表,请参阅数据类型