Generated Types
This page documents what type definitions in TypeSpec are generated as in emitted libraries
Namespace
The namespace for models, enums, and unions will follow the namespace they belong to. You can use @clientNamespace
to override it if needed.
Model in namespace
namespace Service;
model Foo { prop: string;}
from service.models import Foo
foo = Foo(prop="hello")
// TODO
// TODO
As flavor=azure
, Java emitter generates the model classes under models
package.
import service.models.Foo;
Foo foo = new Foo("hello");
Model in sub namespace
namespace Service;
namespace Container { model Foo { prop: string; }}
from service.container.models import Foo
foo = Foo(prop="hello")
// TODO
// TODO
As flavor=azure
, Java emitter generates the model classes under models
package.
import service.container.models.Foo;
Foo foo = new Foo("hello");
Model in namespace with renaming
namespace Service;
@clientNamespace("Service.Container")model Foo { prop: string;}
from service.container.models import Foo
foo = Foo(prop="hello")
// TODO
// TODO
As flavor=azure
, Java emitter generates the model classes under models
package.
import service.container.models.Foo;
Foo foo = new Foo("hello");
Models
Flattening
model Properties { name: string;}
model Foo { @flattenProperty prop: Properties;}
{ "kind": "model", "name": "Foo", "properties": [ { "kind": "property", "name": "prop", "serializedName": "prop", "flatten": true, "optional": false, "type": { "kind": "model", "name": "Properties", "properties": [ { "kind": "property", "name": "name", "serializedName": "name", "flatten": false, "optional": false, "type": { "kind": "string", "encode": "string" } } ] } } ]}
Python will do dynamic flattening, exposing the non-flattening syntax, and dynamically accepting the flattened access.
class Properties(_model_base.Model): name: str = rest_field() """Required."""
class Foo(_model_base.Model): properties: "_models.Properties" = rest_field() """Required."""
__flattened_items = ["properties"]
print(f.properties.name) # Non-flattened access is preferred experienceprint(f.name) # Flattened access is dynamically supported, but not documented
CSharp will generate the model with properties being flattened. During serialization/deserialization, the model will be serialized/deserialized as a non-flattened model.
public partial class Foo{ public Foo(string name) { Argument.AssertNotNull(name, nameof(name));
Name = name; }
public string Name { get; set; }}
public partial class Foo : IUtf8JsonSerializable, IJsonModel<Foo>{ void IJsonModel<Foo>.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { var format = options.Format == "W" ? ((IPersistableModel<Foo>)this).GetFormatFromOptions(options) : options.Format; if (format != "J") { throw new FormatException($"The model {nameof(Foo)} does not support writing '{format}' format."); }
writer.WriteStartObject(); writer.WritePropertyName("properties"u8); writer.WriteStartObject(); writer.WritePropertyName("name"u8); writer.WriteStringValue(Name); writer.WriteEndObject(); writer.WriteEndObject(); }
internal static Foo DeserializeFoo(JsonElement element, ModelReaderWriterOptions options = null) { options ??= ModelSerializationExtensions.WireOptions;
if (element.ValueKind == JsonValueKind.Null) { return null; } string name = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("properties"u8)) { if (property.Value.ValueKind == JsonValueKind.Null) { property.ThrowNonNullablePropertyIsNull(); continue; } foreach (var property0 in property.Value.EnumerateObject()) { if (property0.NameEquals("name"u8)) { name = property0.Value.GetString(); } } } } return new Foo(name); }}
// Please note that this feature is not supported right now, and the model will be generated un-flattened.// Please comment and follow work status on: https://github.com/Azure/autorest.typescript/issues/2164
In Java, @flattenProperty
have no effect on generated libraries.
@Fluentpublic final class Properties { public Properties(); public String getName(); public Properties setName(String name);}
Models with additional properties
Additional properties of any type
Recommend usage:
model Animal { name: string; kind: string; ...Record<unknown>;}
Other usages:
model Animal extends Record<unknown> { name: string; kind: string;}
model Animal is Record<unknown> { name: string; kind: string;}
{ "kind": "model", "name": "Animal", "properties": [ { "kind": "property", "name": "name", "serializedName": "name", "optional": false, "type": { "kind": "string", "encode": "string" } }, { "kind": "property", "name": "kind", "serializedName": "kind", "optional": false, "type": { "kind": "string", "encode": "string" } } ], "additionalProperties": { "kind": "any" }}
Python models are designed to support adding any additional properties.
from .. import _model_basefrom .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field() kind: str = rest_field()
animal = Animal(name="Tom", kind="Cat")animal["friend"] = "Jerry"animal["age"] = 5
public partial class Animal : IJsonModel<Animal> { public Animal(string name, string kind);
public string Name { get; } public string Kind { get; }
public IDictionary<string, BinaryData> AdditionalProperties { get; }}
// RLC inputexport interface Animal extends Record<string, unknown> { name: string; kind: string;}
// RLC outputexport interface AnimalOutput extends Record<string, any> { name: string; kind: string;}
// Modular for both legacy and non legacyexport interface Animal extends Record<string, any> { name: string; kind: string;}
@Fluentpublic final class Animal implements JsonSerializable<Animal> { public Animal(String name, String kind); public String getName(); public String getKind(); public Map<String, Object> getAdditionalProperties(); public Animal setAdditionalProperties(Map<String, Object> additionalProperties);}
Additional properties of specific type
model AnimalProperty { category: string; value: unknown;}
model Animal { name: string; kind: string; ...Record<AnimalProperty>;}
{ "kind": "model", "name": "Animal", "properties": [ { "kind": "property", "name": "name", "serializedName": "name", "optional": false, "type": { "kind": "string", "encode": "string" } }, { "kind": "property", "name": "kind", "serializedName": "kind", "optional": false, "type": { "kind": "string", "encode": "string" } } ], "additionalProperties": { "kind": "model", "name": "AnimalProperty", "properties": [ { "kind": "property", "name": "category", "serializedName": "category", "optional": false, "type": { "kind": "string", "encode": "string" } }, { "kind": "property", "name": "value", "serializedName": "value", "optional": false, "type": { "kind": "any" } } ], "additionalProperties": undefined }}
Python models are designed to support adding any additional properties.
from typing import Anyfrom .. import _model_basefrom .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field() kind: str = rest_field()
class AnimalProperty(_model_base.Model):
category: str = rest_field() value: Any = rest_field()
animal = Animal(name="Tom", kind="Cat")animal["friend"] = AnimalProperty(category="relationship", value="Jerry")animal["age"] = AnimalProperty(category="attribute", value=5)
Due to currently there is no way to know whether a Json could be correctly mapped into the specified type in .Net
, we currently generate any non-primitive value type in additional properties property as BinaryData
.
For typespec:
model Animal { name: string; kind: string; ...Record<AnimalProperty>;}
The C#
generated code is the same as if the type is unknown
:
public partial class Animal : IJsonModel<Animal>{ public Animal(string name, string kind);
public string Name { get; } public string Kind { get; }
public IDictionary<string, BinaryData> AdditionalProperties { get; }}
For typespec with additional properties of primitive types:
model Animal { name: string; kind: string; ...Record<string>;}
The C#
generated code still has the specified type in AdditionalProperties
property:
public partial class Animal : IJsonModel<Animal>{ public Animal(string name, string kind);
public string Name { get; } public string Kind { get; }
public IDictionary<string, string> AdditionalProperties { get; }}
// RLC inputexport interface AnimalProperty { category: string; value: unknown;}export interface Animal extends Record<string, unknown> { name: string; kind: string;}
// RLC outputexport interface AnimalProperty { category: string; value: any;}export interface Animal extends Record<string, any> { name: string; kind: string;}
// Modular for legacy clientsexport interface AnimalProperty { category: string; value: any;}export interface Animal extends Record<string, any> { name: string; kind: string;}
// Modular for non-legacy clientsexport interface AnimalProperty { category: string; value: any;}export interface Animal { name: string; kind: string; additionalProperties: Record<string, AnimalProperty>;}
@Fluentpublic final class Animal implements JsonSerializable<Animal> { public Animal(String name, String kind); public String getName(); public String getKind(); public Map<String, AnimalProperty> getAdditionalProperties(); public Animal setAdditionalProperties(Map<String, AnimalProperty> additionalProperties);}
Additional properties of union type
model Animal { name: string; kind: string; ...Record<string | int32>;}
model Animal { name: string; kind: string; ...Record<string>; ...Record<int32>;}
{ "kind": "model", "name": "Animal", "properties": [ { "kind": "property", "name": "name", "serializedName": "name", "optional": false, "type": { "kind": "string", "encode": "string" } }, { "kind": "property", "name": "kind", "serializedName": "kind", "optional": false, "type": { "kind": "string", "encode": "string" } } ], "additionalProperties": { "kind": "union", "name": "AnimalAdditionalProperty", "generatedName": true, "values": [ { "kind": "string", "encode": "string" }, { "kind": "int32" } ] }}
Python models are designed to support adding any additional properties.
from .. import _model_basefrom .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field() kind: str = rest_field()
animal = Animal(name="Tom", kind="Cat")animal["friend"] = "Jerry"animal["age"] = 5
public partial class Animal : IJsonModel<Animal>{ public Animal(string name, string kind);
public string Name { get; } public string Kind { get; }
public IDictionary<string, BinaryData> AdditionalProperties { get; }}
// RLC input and outputexport interface Animal extends Record<string, string | number> { name: string; kind: string;}
// Modular for legacy and non-legacy clientsexport interface Animal extends Record<string, string | number> { name: string; kind: string;}
@Fluentpublic final class Animal implements JsonSerializable<Animal> { public Animal(String name, String kind); public String getName(); public String getKind(); public Map<String, BinaryData> getAdditionalProperties(); public Animal setAdditionalProperties(Map<String, BinaryData> additionalProperties);}
Additional properties of nullable type
model Animal { name: string; kind: string; ...Record<string | null>;}
{ "kind": "model", "name": "Animal", "properties": [ { "kind": "property", "name": "name", "serializedName": "name", "optional": false, "type": { "kind": "string", "encode": "string" } }, { "kind": "property", "name": "kind", "serializedName": "kind", "optional": false, "type": { "kind": "string", "encode": "string" } } ], "additionalProperties": { "kind": "nullable", "valueType": { "kind": "string", "encode": "string" } }}
Python models are designed to support adding any additional properties.
from .. import _model_basefrom .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field() kind: str = rest_field()
animal = Animal(name="Tom", kind="Cat")animal["friend"] = "Jerry"animal["alert"] = None
public partial class Animal : IJsonModel<Animal>{ public Animal(string name, string kind);
public string Name { get; } public string Kind { get; }
public IDictionary<string, string> AdditionalProperties { get; }}
// RLC input and outputexport interface Animal extends Record<string, string | null> { name: string; kind: string;}
// Modular for legacy and non-legacy clientsexport interface Animal extends Record<string, string | null> { name: string; kind: string;}
@Fluentpublic final class Animal implements JsonSerializable<Animal> { public Animal(String name, String kind); public String getName(); public String getKind(); public Map<String, String> getAdditionalProperties(); public Animal setAdditionalProperties(Map<String, String> additionalProperties);}
Discriminator
TypeSpec uses @discriminator
decorator to add a discriminator to a model.
TypeSpec now has two ways to represent a discriminated set.
- Use model
@discriminator("kind")model Cat { kind: string;}
model Siamese extends Cat { kind: "siamese";}
model Ragdoll extends Cat { kind: "ragdoll";}
The type of the discriminator property could be an enum (extensible or fixed):
@discriminator("kind")model Cat { kind: CatKind;}
union CatKind { string, Siamese: "siamese", Ragdoll: "ragdoll",}
model Siamese extends Cat { kind: CatKind.Siamese;}
model Ragdoll extends Cat { kind: CatKind.Ragdoll;}
- Use union
@discriminator("kind")union Cat { Siamese, Ragdoll,}
model Siamese {}
model Ragdoll {}
TCGC currently only supports the discriminated set based on models, discriminated union is not supported yet.
This is a brief structure of the models in a discriminated set in the output of TCGC.
{ "models": [ { "kind": "model", "name": "Cat", "properties": [ { "kind": "property", "name": "kind", "type": { "kind": "string" }, "discriminator": true } ], "discriminatorProperty": { // the same instance of the property in the properties list here }, "discriminatedSubtype": { "siamese": { "kind": "model", "name": "Siamese", "properties": [], "discriminatorValue": "siamese" }, "ragdoll": { "kind": "model", "name": "Ragdoll", "properties": [], "discriminatorValue": "ragdoll" } } }, { // the same instance of the model Siamese as we have above in `discriminatedSubtype` property }, { // the same instance of the model Ragdoll as we have above in `discriminatedSubtype` property } ]}
from .. import _model_basefrom .._model_base import rest_discriminator, rest_field
class Cat(_model_base.Model): kind: str = rest_discriminator(name="kind")
class Siamese(Cat): kind: Literal["siamese"] = rest_discriminator(name="kind")
class Ragdoll(Cat): kind: Literal["ragdoll"] = rest_discriminator(name="kind")
In .Net generated code, the discriminator property will be generated as internal by default, but configurable to be public.
public abstract partial class Cat{ protected Cat() { }
internal string Kind { get; set; }}
public partial class Siamese : Cat{ public Siamese() : base() { Kind = "siamese"; }}
public partial class Ragdoll : Cat{ public Ragdoll() : base() { Kind = "ragdoll"; }}
// RLC input modelsexport interface Siamese extends CatParent { kind: "siamese";}
export interface Ragdoll extends CatParent { kind: "ragdoll";}
export type Cat = CatParent | Siamese | Ragdoll;
// RLC output modelsexport interface CatOutputParent { kind: string;}
export interface SiameseOutput extends CatOutputParent { kind: "siamese";}
export interface RagdollOutput extends CatOutputParent { kind: "ragdoll";}
export type CatOutput = CatOutputParent | SiameseOutput | RagdollOutput;
// Modular models/** model interface Cat */export interface Cat { kind: string;}
/** Alias for CatUnion */export type CatUnion = Siamese | Ragdoll | Cat;
/** model interface Siamese */export interface Siamese extends Cat { kind: "siamese";}/** model interface Ragdoll */export interface Ragdoll extends Cat { kind: "ragdoll";}
public class Cat implements JsonSerializable<Cat> { public Cat(); public String getKind();}
public final class Ragdoll extends Cat { public Ragdoll(); public String getKind();}
public final class Siamese extends Cat { public Siamese(); public String getKind();}
// CatClassification provides polymorphic access to related types.// Call the interface's GetCat() method to access the common type.// Use a type switch to determine the concrete type. The possible types are:// - *Cat, *Ragdoll, *Siamesetype CatClassification interface { // GetCat returns the Cat content of the underlying type. GetCat() *Cat}
type Cat struct { // REQUIRED Kind *string}
// GetCat implements the CatClassification interface for type Cat.func (c *Cat) GetCat() *Cat { return c }
type Ragdoll struct { // CONSTANT; undefinedField has constant value "ragdoll", any specified value is ignored. Kind *string}
// GetCat implements the CatClassification interface for type Ragdoll.func (e *Ragdoll) GetCat() *Cat { return &Cat{ Kind: e.Kind, }}
type Siamese struct { // CONSTANT; undefinedField has constant value "siamese", any specified value is ignored. Kind *string}
// GetCat implements the CatClassification interface for type Siamese.func (e *Siamese) GetCat() *Cat { return &Cat{ Kind: e.Kind, }}
Nullable
TypeSpec uses | null
to represent nullable types. Nullability is handled differently in languages, but emitter authors will find information
about nullability by inspecting the type of a property.
model Foo { basicNullableProperty: string | null; modelNullableProperty: Bar | null; unionNullableProperty: Bar | Baz | null; enumNullableProperty: LR | null;}
model Bar { prop: string;}
model Baz { prop: int32;}
enum LR { left, right,}
A nullable type has kind nullable
and property valueType
. The kind of the type tells you the property is nullable, while the valueType
tells you the underlying type you want to generate.
{ "kind": "model", "name": "Foo", "properties": [ { "kind": "property", "name": "basicNullableProperty", "serializedName": "basicNullableProperty", "optional": false, "type": { "kind": "nullable", "valueType": { "kind": "string", "encode": "string" } } }, { "kind": "property", "name": "modelNullableProperty", "serializedName": "modelNullableProperty", "optional": false, "type": { "kind": "nullable", "valueType": { "kind": "model", "name": "Bar", "properties": [ { "kind": "property", "name": "prop", "serializedName": "prop", "optional": false, "type": { "kind": "string", "encode": "string" } } ] } } }, { "kind": "property", "name": "unionNullableProperty", "serializedName": "unionNullableProperty", "optional": false, "type": { "kind": "nullable", "valueType": { "kind": "union", "values": [ { "kind": "model", "name": "Bar", "properties": [ { "kind": "property", "name": "prop", "serializedName": "prop", "optional": false, "type": { "kind": "string", "encode": "string" } } ] }, { "kind": "model", "name": "Baz", "properties": [ { "kind": "property", "name": "prop", "serializedName": "prop", "optional": false, "type": { "kind": "int32", "encode": "int32" } } ] } ] } } }, { "kind": "property", "name": "enumNullableProperty", "serializedName": "enumNullableProperty", "optional": false, "type": { "kind": "nullable", "valueType": { "kind": "enum", "name": "LR", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": false } } } ]}
Python treat nullable as optional. If you actually want to send the value null
to the service without the property being ignored, you can send in corehttp.serialization.NULL
. Python does not restrict you from setting any property to this value.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class Bar(_model_base.Model): prop: Optional[str] = rest_field()
class Baz(_model_base.Model): prop: Optional[str] = rest_field()
class LR(str, Enum, metaclass=CaseInsensitiveEnumMeta): LEFT = "left" RIGHT = "right"
class Foo(_model_base.Model): basicNullableProperty: Optional[str] = rest_field() modelNullableProperty: Optional["_models.Bar"] = rest_field() unionNullableProperty: Optional[Union["_models.Bar", "_models.Baz"]] = rest_field() enumNullableProperty: Optional["LR"] = rest_field()
TODO
TODO
TODO
Unions
Union of literals with same type
All emitters will generate their version of a closed enum.
union LR { left: "left", right: "right",}
{ "kind": "enum", "name": "LR", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": true}
Python never generates closed enum by design. We will always permit users to pass in additional values.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class LR(str, Enum, metaclass=CaseInsensitiveEnumMeta): LEFT = "left" RIGHT = "right"
public enum LR{ Left, Right}
Serialization/deserialization will respect the value defined, in this case it is “left” for LR.Left
and “right” for LR.Right
respectively.
export type LR = "left" | "right";
public enum LR { LEFT("left"), RIGHT("right");}
Inline union of literals with same type
This is union defined inline at point of usage.
model Widget { horizontal: "left" | "right";}
{ "kind": "enum", "name": "WidgetHorizontals", "generatedName": true, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": true}
Python generates this as a union of literals, not as enum. We also don’t generate a closed set of literals.
from typing import Literal, Union
model Widget: horizontal: Union[Literal["left"] | Literal["right"] | str]
public partial class Widget{ public WidgetHorizontal Horizontal;}public enum WidgetHorizontal{ Left, Right}
export interface Widget { horizontal: "left" | "right";}
public enum WidgetHorizontal { LEFT("left"), RIGHT("right");}
Union of basic type and literals of that type
Each language will generate their version of an open enum.
union Colors { string, red: "red", blue: "blue",}
{ "kind": "enum", "name": "Colors", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "red", "value": "red" }, { "kind": "enumvalue", "name": "blue", "value": "blue" } ], "isFixed": false, "isUnionAsEnum": true}
Python generates open enum again here.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class Colors(str, Enum, metaclass=CaseInsensitiveEnumMeta): RED = "red" BLUE = "blue"
public readonly partial struct Colors : IEquatable<Colors>{ private const string RedValue = "red"; private const string BlueValue = "blue"; public static Colors Red { get; } = new Colors(RedValue); public static Colors Blue { get; } = new Colors(BlueValue);}
export type Colors = string | "red" | "blue";
public final class Colors extends ExpandableStringEnum<Colors> { public static final Colors RED = fromString("red"); public static final Colors BLUE = fromString("blue");}
Inline union of basic type and literals of that type
This is union defined inline at point of usage which include the base type as an option.
model Widget { color: "red" | "blue" | string;}
{ "kind": "enum", "name": "WidgetColors", "generatedName": true, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "red", "value": "red" }, { "kind": "enumvalue", "name": "blue", "value": "blue" } ], "isFixed": false, "isUnionAsEnum": true}
Python generates a union of literals again.
from typing import Literal, Union
model Widget: color: Union[Literal["red"] | Literal["blue"] | str]
public partial class Widget{ public WidgetColor Color;}public readonly partial struct WidgetColor : IEquatable<WidgetColor>{ private const string RedValue = "red"; private const string BlueValue = "blue"; public static WidgetColor Red { get; } = new WidgetColor(RedValue); public static WidgetColor Blue { get; } = new WidgetColor(BlueValue);}
export interface Widget { color: "red" | "blue" | string;}
public final class WidgetColor extends ExpandableStringEnum<Colors> { public static final Color RED = fromString("red"); public static final Color BLUE = fromString("blue");}
Union of other union/enum, basic type and literals of that type
import "@azure-tools/typespec-azure-resource-manager";
union ProvisioningState { string, "InProgress", Azure.ResourceManager.ResourceProvisioningState,}
For union of other union or enum. TCGC will do the flatten according to the flag.
With flatten-union-as-enum
flagged true
:
{ "kind": "enum", "name": "ProvisioningState", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "InProgress", "value": "InProgress" }, { "kind": "enumvalue", "name": "Succeeded", "value": "Succeeded" }, { "kind": "enumvalue", "name": "Failed", "value": "Failed" }, { "kind": "enumvalue", "name": "Canceled", "value": "Canceled" } ], "isFixed": false, "isUnionAsEnum": true}
With flatten-union-as-enum
flagged false
:
{ "kind": "union", "name": "ProvisioningState", "generatedName": false, "values": [ { "kind": "string" }, { "kind": "constant", "value": "InProgress", "valueType": { "kind": "string" } }, { "kind": "enum", "name": "ResourceProvisioningState", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "Succeeded", "value": "Succeeded" }, { "kind": "enumvalue", "name": "Failed", "value": "Failed" }, { "kind": "enumvalue", "name": "Canceled", "value": "Canceled" } ], "isFixed": true, "isUnionAsEnum": false } ]}
Python generates a single open enum.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class ProvisioningState(str, Enum, metaclass=CaseInsensitiveEnumMeta): INPROGRESS = "InProgress" SUCCEEDED = "Succeeded" FAILED = "Failed" CANCELED = "Canceled"
public readonly partial struct ProvisioningState : IEquatable<ProvisioningState>{ private const string SucceededValue = "Succeeded"; private const string FailedValue = "Failed"; private const string CanceledValue = "Canceled"; private const string InProgressValue = "InProgress";
public static ProvisioningState Succeeded { get; } = new ProvisioningState(SucceededValue); public static ProvisioningState Failed { get; } = new ProvisioningState(FailedValue); public static ProvisioningState Canceled { get; } = new ProvisioningState(CanceledValue); public static ProvisioningState InProgress { get; } = new ProvisioningState(InProgressValue);}
export type ResourceProvisioningState = "Succeeded" | "Failed" | "Canceled";// NOTE: extensible enum design may change in JSexport type ProvisioningState = string | "InProgress" | ResourceProvisioningState;
public final class ProvisioningState extends ExpandableStringEnum<ProvisioningState> { public static final ProvisioningState INPROGRESS = fromString("InProgress"); public static final ProvisioningState SUCCEEDED = fromString("Succeeded"); public static final ProvisioningState FAILED = fromString("Failed"); public static final ProvisioningState CANCELED = fromString("Canceled");}
Union of other unions of literals with same type
union LR { left: "left", right: "right",}
union UD { up: "up", down: "down",}
union Orientation { LR, UD,}
For union of other union or enum. TCGC will do the flatten according to the flag.
With flatten-union-as-enum
flagged true
:
{ "kind": "enum", "name": "Orientation", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" }, { "kind": "enumvalue", "name": "up", "value": "up" }, { "kind": "enumvalue", "name": "down", "value": "down" } ], "isFixed": true, "isUnionAsEnum": true}
With flatten-union-as-enum
flagged false
:
{ "kind": "union", "name": "Orientation", "generatedName": false, "values": [ { "kind": "enum", "name": "LR", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": true }, { "kind": "enum", "name": "UD", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "up", "value": "up" }, { "kind": "enumvalue", "name": "down", "value": "down" } ], "isFixed": true, "isUnionAsEnum": true } ]}
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class Orientation(str, Enum, metaclass=CaseInsensitiveEnumMeta): LEFT = "left" RIGHT = "right" UP = "up" DOWN = "down"
public enum Orientation{ Left, Right, Up, Down}
export type LR = "left" | "right";export type UD = "up" | "down";export type Orientation = LR | UD;
public enum Orientation { LEFT("left"), RIGHT("right"), UP("up"), DOWN("down");}
Inline union of other unions of literals with same type
union LR { left: "left", right: "right",}
union UD { up: "up", down: "down",}
model Widget { orientation: LR | UD;}
For union of other union or enum. TCGC will do the flatten according to the flag.
With flatten-union-as-enum
flagged true
:
{ "kind": "enum", "name": "WidgetOrientations", "generatedName": true, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" }, { "kind": "enumvalue", "name": "up", "value": "up" }, { "kind": "enumvalue", "name": "down", "value": "down" } ], "isFixed": true, "isUnionAsEnum": true}
With flatten-union-as-enum
flagged false
:
{ "kind": "union", "name": "WidgetOrientations", "generatedName": true, "values": [ { "kind": "enum", "name": "LR", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": true }, { "kind": "enum", "name": "UD", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "up", "value": "up" }, { "kind": "enumvalue", "name": "down", "value": "down" } ], "isFixed": true, "isUnionAsEnum": true } ]}
Since this is inline, Python will generate this as a single union of all possible literal values.
from typing import Literal
type WidgetOrientation = "left" | "right" | "up" | "down" | str
model Widget: orientation: WidgetOrientation
public partial class Widget{ public WidgetOrientation Orientation;}public enum WidgetOrientation{ Left, Right, Up, Down}
export interface Widget { orientation: LR | UD;}
export type LR = "left" | "right";export type UD = "up" | "down";
public enum WidgetOrientation { LEFT("left"), RIGHT("right"), UP("up"), DOWN("down");}
Union with multiple types
These are unions where the values don’t share same type.
model Shirt { sizing: 32 | 34 | int32 | "small" | "medium" | string;}
{ "kind": "union", "name": "ShirtSizings", "generatedName": true, "values": [ { "kind": "constant", "value": 32, "valueType": { "kind": "int32" } }, { "kind": "constant", "value": 34, "valueType": { "kind": "int32" } }, { "kind": "constant", "value": "small", "valueType": { "kind": "string" } }, { "kind": "constant", "value": "medium", "valueType": { "kind": "string" } }, { "kind": "string" } ]}
Python will generate this as a union since these entries don’t share the same type
from typing import Literal
type ShirtSizing = Literal[32] | Literal[34] | int | Literal["small"] | Literal["medium"] | str
model Shirt: sizing: ShirtSizing
public partial class Shirt{ public BinaryData Shirt;}
export interface Shirt { sizing: 32 | 34 | number | "small" | "medium" | string;}
public final class Shirt { private BinaryData sizing;}
Enums
Standard
Standard enums will be generated as closed enums.
enum LR { left, right,}
{ "kind": "enum", "name": "LR", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": false}
Python never generates closed enums by design. We will always permit users to pass in additional values.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class LR(str, Enum, metaclass=CaseInsensitiveEnumMeta): LEFT = "left" RIGHT = "right"
public enum LR{ Left, Right}
export type LR = "left" | "right";
public enum LR { LEFT("left"), RIGHT("right");}
Versioning Enums
@versioned(Versions)@servicenamespace Service;
enum Versions { v1, v2,}
{ "kind": "enum", "name": "Versions", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "v1", "value": "v1" }, { "kind": "enumvalue", "name": "v2", "value": "v2" } ], "isFixed": true, "isUnionAsEnum": false, "usage": 8}
# Python does not generate the enum used for versioning
// CSharp does not generate the enum used for versioning
// JS does not generate the enum used for versioning
public enum ServiceServiceVersion implements ServiceVersion { V1("v1"), V2("v2");}
Spread
Spreading enums will return the resultant enum as a new single closed enum.
enum LR { left, right,}
enum UD { up, down,}
enum Orientation { ...LR, ...UD,}
{ "kind": "enum", "name": "Orientation", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" }, { "kind": "enumvalue", "name": "up", "value": "up" }, { "kind": "enumvalue", "name": "down", "value": "down" } ], "isFixed": true, "isUnionAsEnum": false}
Python generates one open enum, because Python never generates an enum as fully closed.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class Orientation(str, Enum, metaclass=CaseInsensitiveEnumMeta): LEFT = "left" RIGHT = "right" UP = "up" DOWN = "down"
public enum Orientation{ Left, Right, Up, Down}
export type Orientation = "left" | "right" | "up" | "down";
public enum Orientation { LEFT("left"), RIGHT("right"), UP("up"), DOWN("down");}
Scalars
Encoding
We will take the @encode
decorator into account, determining how we serialize inputted scalars to send over the wire.
model Test { @encode(DateTimeKnownEncoding.rfc3339) prop: utcDateTime;}
{ "kind": "property", "name": "prop", "type": { "kind": "utcDateTime", "encode": "rfc3339", "wireType": { "kind": "string" } }}
serialized_prop = json.dumps(prop, cls=SdkJSONEncoder, format="rfc3339")
// Internal implementationutf8JsonWriter.WriteStringValue(Prop.ToString());
TODO;
// Internal implementationjsonWriter.writeStringField("prop", this.value == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(this.value));
When you specify an encoding type, say that you want to encode an integer as a string, that will also be represented in our generated SDKs.
model Test { @encode(string) prop: int64;}
{ "kind": "property", "name": "prop", "type": { "kind": "int64", "encode": "string", "wireType": { "kind": "string" } }}
serialized_prop = json.dumps(prop, cls=SdkJSONEncoder, format="string")
TODO
TODO;
// Internal implementationjsonWriter.writeStringField("prop", Objects.toString(this.value, null));