Condividi tramite


Tipi di dati definiti dall'utente in Bicep

Informazioni su come creare tipi di dati definiti dall'utente in Bicep. Per i tipi di dati definiti dal sistema, vedere Tipi di dati.

Per usare questa funzionalità è necessaria l'interfaccia della riga di comando Bicep versione 0.12.X o successiva .

Sintassi

È possibile usare l'istruzione type per creare tipi di dati definiti dall'utente. Inoltre, è anche possibile usare espressioni di tipo in alcune posizioni per definire tipi personalizzati.

type <user-defined-data-type-name> = <type-expression>

L'espressione Decorator @allowed è consentita solo nelle paramistruzioni. Per dichiarare un tipo con un set di valori predefiniti in un typeoggetto , usare la sintassi del tipo di unione.

Le espressioni di tipo valide includono:

  • I riferimenti simbolici sono identificatori che fanno riferimento a un tipo di ambiente (ad esempio string o int) o a un simbolo di tipo definito dall'utente dichiarato in un'istruzione type:

    // Bicep data type reference
    type myStringType = string
    
    // user-defined type reference
    type myOtherStringType = myStringType
    
  • I valori letterali primitivi, inclusi stringhe, interi e booleani, sono espressioni di tipo valide. Ad esempio:

    // 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
    
  • È possibile dichiarare i tipi di matrice aggiungendo [] a qualsiasi espressione di tipo valida:

    // 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)[]
    
  • I tipi di oggetto contengono zero o più proprietà tra parentesi graffe:

    type storageAccountConfigType = {
      name: string
      sku: string
    }
    

    Ogni proprietà in un oggetto è costituita da una chiave e un valore, separati da due punti :. La chiave può essere qualsiasi stringa, con valori nonidentifier racchiusi tra virgolette e il valore può essere qualsiasi tipo di espressione.

    Le proprietà sono obbligatorie a meno che non abbiano un marcatore ? di facoltatività dopo il valore della proprietà. Ad esempio, la proprietà sku nell'esempio seguente è facoltativa:

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

    Gli elementi Decorator possono essere usati sulle proprietà. * può essere usato per rendere tutti i valori necessari un vincolo. È comunque possibile definire proprietà aggiuntive quando si usa *. In questo esempio viene creato un oggetto che richiede una chiave di tipo int id denominato e che tutte le altre voci dell'oggetto devono essere un valore stringa lungo almeno 10 caratteri.

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

    L'esempio seguente illustra come usare la sintassi dei tipi di unione per elencare un set di valori predefiniti:

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

    Ricorsione

    I tipi di oggetto possono usare ricorsione diretta o indiretta, purché almeno la gamba del percorso verso il punto di ricorsione sia facoltativa. Ad esempio, la definizione myObjectType nell'esempio seguente è valida perché la proprietà recursiveProp ricorsiva diretta è facoltativa:

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

    Tuttavia, la definizione di tipo seguente non sarebbe valida perché nessuno tra level1, level2, level3, level4 o level5 è facoltativo.

    type invalidRecursiveObjectType = {
      level1: {
        level2: {
          level3: {
            level4: {
              level5: invalidRecursiveObjectType
            }
          }
        }
      }
    }
    
  • Gli operatori unari Bicep possono essere usati con valori letterali interi e booleani o riferimenti a simboli letterali di tipo integer o booleano:

    type negativeIntLiteral = -10
    type negatedIntReference = -negativeIntLiteral
    
    type negatedBoolLiteral = !true
    type negatedBoolReference = !negatedBoolLiteral
    
  • Le unioni possono includere un numero qualsiasi di espressioni di tipo letterale. I tipi di unione vengono convertiti nel vincolo allowed-value (valore consentito) in Bicep, quindi solo i valori letterali sono consentiti come membri.

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

Oltre a essere usato nell'istruzione type, le espressioni di tipo possono essere usate anche in queste posizioni per la creazione di tipi di dati definiti dall'utente:

  • Come clausola type di un'istruzione param. Ad esempio:

    param storageAccountConfig {
      name: string
      sku: string
    }
    
  • Dopo : in una proprietà del tipo di oggetto. Ad esempio:

    param storageAccountConfig {
     name: string
      properties: {
        sku: string
      }
    } = {
      name: 'store$(uniqueString(resourceGroup().id)))'
      properties: {
        sku: 'Standard_LRS'
      }
    }
    
  • Prima di [] in un'espressione di tipo matrice. Ad esempio:

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

Un tipico file Bicep per creare un account di archiviazione è simile al seguente:

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 i tipi di dati definiti dall'utente, può essere simile al seguente:

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

Elevare il livello di errore

Per impostazione predefinita, la dichiarazione di un tipo di oggetto in Bicep consente di accettare proprietà aggiuntive di qualsiasi tipo. Ad esempio, il bicep seguente è valido ma genera un avviso di [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'
}

L'avviso informa che il tipo anObject non include una proprietà denominata otionalProperty. Anche se non si verificano errori durante la distribuzione, il compilatore Bicep presuppone che otionalProperty sia un errore di digitazione, che si intende usare optionalProperty , ma lo ha digitato in modo non corretto e segnalare l'incoerenza.

Per inoltrare questi avvisi agli errori, applicare l'elemento @sealed() Decorator al tipo di oggetto:

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

Per ottenere gli stessi risultati, applicare l'elemento @sealed() Decorator alla param dichiarazione:

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

Il motore di distribuzione arm controlla anche i tipi sealed per verificare la presenza di proprietà aggiuntive. Se si specificano proprietà aggiuntive per i parametri sealed, viene generato un errore di convalida, causando l'esito negativo della distribuzione. Ad esempio:

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

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

Tipo di dati unione con tag

Per dichiarare un tipo di dati unione con tag personalizzato all'interno di un file Bicep, è possibile posizionare un discriminator elemento Decorator sopra una dichiarazione di tipo definita dall'utente. Per usare questo elemento decorator è necessaria l’interfaccia della riga di comando di Bicep versione 0.21.X o successiva. Nell'esempio seguente viene illustrato come dichiarare un tipo di dati unione con tag:

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

Per altre informazioni, vedere Tipo di dati unione con tag personalizzati.

Tipi di importazione tra file Bicep

Solo i tipi di dati definiti dall'utente che contengono l'elemento Decorator @export() possono essere importati in altri modelli.

L'esempio seguente consente di importare i due tipi di dati definiti dall'utente da altri modelli:

@export()
type myStringType = string

@export()
type myOtherStringType = myStringType

Per altre informazioni, vedere Importare tipi di dati definiti dall'utente.

Passaggi successivi

  • Per un elenco dei tipi di dati Bicep, vedere Tipi di dati.