Tipos de dados definidos pelo usuário no Bicep

Saiba como criar tipos de dados definidos pelo usuário no Bicep. Para tipos de dados definidos pelo sistema, consulte Tipos de dados.

A CLI do Bicep versão 0.12.X ou superior é necessária para usar esse recurso.

Defina os tipos

Você pode usar a instrução type para criar tipos de dados definidos pelo usuário. Além disso, você também pode usar expressões de tipo em alguns locais para definir tipos personalizados.

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

O @allowed decorador só é permitido em param declarações. Para declarar um tipo com um conjunto de valores predefinidos em um type, use a sintaxe de tipo união.

As expressões de tipo válidas incluem:

  • Referências simbólicas são identificadores que se referem a um tipo de ambiente (como string ou int) ou a um símbolo de tipo definido pelo usuário declarado em uma instrução type:

    // Bicep data type reference
    type myStringType = string
    
    // user-defined type reference
    type myOtherStringType = myStringType
    
  • Literais primitivos, incluindo cadeias de caracteres, inteiros e boolianos, são expressões de tipo válidas. Por exemplo:

    // 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
    
  • Você pode declarar tipos de matriz anexando [] a qualquer expressão de tipo válida:

    // 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)[]
    
  • Os tipos de objeto contêm zero ou mais propriedades entre colchetes:

    type storageAccountConfigType = {
      name: string
      sku: string
    }
    

    Cada propriedade em um objeto consiste em uma chave e um valor, separados por dois pontos :. A chave pode ser qualquer cadeia de caracteres, com valores não identificadores entre aspas, e o valor pode ser qualquer tipo de expressão.

    As propriedades são necessárias, a menos que tenham um marcador de opcionalidade ? após o valor da propriedade. Por exemplo, a propriedade sku no seguinte exemplo é opcional:

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

    Decoradores podem ser usados em propriedades. * pode ser usado para fazer com que todos os valores exijam uma restrição. Propriedades adicionais ainda podem ser definidas ao usar *. Este exemplo cria um objeto que requer uma chave do tipo int chamada ID, e que todas as outras entradas no objeto devem ter um valor de cadeia de caracteres com pelo menos 10 caracteres de comprimento.

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

    O exemplo a seguir mostra como usar a sintaxe do tipo de união para listar um conjunto de valores predefinidos:

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

    Recursão

    Os tipos de objetos podem usar recursão direta ou indireta, desde que pelo menos um dos caminhos para o ponto de recursão seja opcional. Por exemplo, a definição myObjectType no seguinte exemplo é válida porque a propriedade recursiveProp recursiva diretamente é opcional:

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

    Mas a seguinte definição de tipo não são válidas, pois nem level1, level2, level3, level4 ou level5 são opcionais.

    type invalidRecursiveObjectType = {
      level1: {
        level2: {
          level3: {
            level4: {
              level5: invalidRecursiveObjectType
            }
          }
        }
      }
    }
    
  • Os operadores unários do Bicep podem ser usados com literais inteiros e boolianos ou referências a símbolos inteiros ou boolianos de tipo literal:

    type negativeIntLiteral = -10
    type negatedIntReference = -negativeIntLiteral
    
    type negatedBoolLiteral = !true
    type negatedBoolReference = !negatedBoolLiteral
    
  • As uniões podem incluir qualquer número de expressões do tipo literal. Os tipos de união são convertidos na restrição de valor permitido no Bicep, portanto, somente literais são permitidos como membros.

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

Além de serem usadas na instrução type, as expressões de tipo também podem ser usadas nestes locais para criar tipos de dados definidos pelo usuário:

  • Como a cláusula de tipo de uma instrução param. Por exemplo:

    param storageAccountConfig {
      name: string
      sku: string
    }
    
  • Seguindo o : em uma propriedade de tipo de objeto. Por exemplo:

    param storageAccountConfig {
     name: string
      properties: {
        sku: string
      }
    } = {
      name: 'store$(uniqueString(resourceGroup().id)))'
      properties: {
        sku: 'Standard_LRS'
      }
    }
    
  • Anterior a [] em uma expressão de tipo de matriz. Por exemplo:

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

Um arquivo Bicep típico para criar uma conta de armazenamento é semelhante a:

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'
}

Usando tipos de dados definidos pelo usuário, ele pode ser semelhante a:

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'
}

Usar decoradores

Os decoradores são escritos no formato @expression e são colocados acima das declarações do tipo de dados definido pelo usuário. A tabela a seguir mostra os decoradores disponíveis para os tipos de dados definidos pelo usuário.

Decorador Argument Descrição
descrição string Fornece descrições para o tipo de dados definido pelo usuário.
discriminator string Use esse decorador para garantir que a subclasse correta seja identificada e gerenciada.
exportar nenhum Indica que o tipo de dados definido pelo usuário está disponível para importação por outro arquivo Bicep.
sealed nenhum Eleve o BCP089 de aviso para erro quando um nome de propriedade de um tipo de dados definido pelo usuário for provavelmente um erro de digitação. Para obter mais informações, consulte Elevar nível de erro.

Os decoradores estão no namespace sys. Se você precisar diferenciar um decorador de outro item com o mesmo nome, preceda o decorador com sys. Por exemplo, se o seu arquivo Bicep incluir uma variável denominada description, você deverá adicionar o namespace sys ao usar o decorador descrição.

Discriminador

Confira Tipo de dado de união com marcação.

Descrição

Adicione uma descrição ao tipo de dados definido pelo usuário. Decoradores podem ser usados em propriedades. Por exemplo:

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

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

O texto formatado em Markdown pode ser usado para o texto da descrição.

Export

Use @export() para compartilhar o tipo de dados definido pelo usuário com outros arquivos Bicep. Para obter mais informações, consulte Exportar variáveis, tipos e funções.

Selado

Consulte Elevar nível de erro.

Elevar o nível de erro

Por padrão, a declaração de um tipo de objeto no Bicep permite que ele aceite propriedades adicionais de qualquer tipo. Por exemplo, o Bicep a seguir é válido, mas gera um aviso de [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'
}

O aviso informa que o tipo anObject não inclui uma propriedade chamada otionalProperty. Embora nenhum erro ocorra durante a implantação, o compilador Bicep assume que otionalProperty é um erro de digitação, que você pretendia usar optionalProperty, mas o escreveu incorretamente, e o alerta sobre a inconsistência.

Para transformar esses avisos em erros, aplique o decorador @sealed() ao tipo de objeto:

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

Você obtém os mesmos resultados aplicando o decorador @sealed() à declaração param:

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

O mecanismo de implantação do ARM também verifica tipos selados em busca de propriedades adicionais. Fornecer quaisquer propriedades extras para parâmetros selados resulta em um erro de validação, causando a falha na implantação. Por exemplo:

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

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

Tipo de dados de união marcado

Para declarar um tipo de dados de união com tag personalizada em um arquivo Bicep, você pode colocar um decorador discriminator acima de uma declaração de tipo definida pelo usuário. A CLI do Bicep versão 0.21.X ou superior é necessária para usar esse decorador. O exemplo a seguir mostra como declarar um tipo de dados de união marcado:

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

Para obter mais informações, veja Tipo de dados de união com marcas personalizadas.

Próximas etapas

  • Para obter uma lista dos tipos de data do Bicep, consulte Tipos de dados.