Legacy Hierarchy Building
This document explains how to use the @Azure.ClientGenerator.Core.Legacy.hierarchyBuilding decorator to change the base type of a model in generated client SDKs.
Overview
Section titled “Overview”The @hierarchyBuilding decorator changes the base type (parent class) of a model in the generated SDK type graph. It does not validate property presence at decoration time. Instead, property reconciliation happens during SDK type graph building.
Use @hierarchyBuilding when you need to:
- Rebase a model onto a different ancestor in the inheritance chain (e.g., skip intermediate models)
- Rebase a model onto an unrelated base that shares common properties (e.g., brownfield ARM resources onto
TrackedResource) - Create multi-level discriminated hierarchies in generated SDKs
Property Reconciliation Rules
Section titled “Property Reconciliation Rules”When the decorator is applied, the following rules govern how properties are reconciled:
1. Property Lifting
Section titled “1. Property Lifting”Properties from removed intermediate ancestors (between the target’s original parent and the new base) are “lifted” onto the rebased model as its own properties.
model C { c?: string;}model B extends C { b?: string;}@Azure.ClientGenerator.Core.Legacy.hierarchyBuilding(C)model A extends B { a?: string;}// SDK result: A extends C. A.properties = { a, b }. C.properties = { c }.// 'b' was lifted from removed intermediate B.2. Duplicate Dropping
Section titled “2. Duplicate Dropping”Properties whose names are supplied by the new base chain are dropped from the model (they are inherited instead).
model B { propB: string;}model A { ...B; propA: string;}@@Azure.ClientGenerator.Core.Legacy.hierarchyBuilding(A, B);// SDK result: A extends B. A.properties = { propA }. B.properties = { propB }.// propB was A's own property via spread, but is now supplied by new base → dropped.3. Type Compatibility Check
Section titled “3. Type Compatibility Check”When dropping a property, if the type on the dropped property is incompatible with the same-named property on the new base chain, a legacy-hierarchy-building-conflict warning with property-type-mismatch message is emitted. The property is still dropped.
model C { shared?: int32;}model OldBase { shared?: string; // different type than C.shared}@Azure.ClientGenerator.Core.Legacy.hierarchyBuilding(C)model A extends OldBase { a?: string;}// SDK result: A extends C. A.properties = { a }.// Warning emitted: 'shared' type mismatch (string vs int32).Compatible types are silently dropped without warnings:
scalar azureLocation extends string;model C { kind: string; location: string;}model OldBase { kind: "old"; location: azureLocation;}@Azure.ClientGenerator.Core.Legacy.hierarchyBuilding(C)model A extends OldBase { a?: string;}// SDK result: A extends C. A.properties = { a }.// No warning: literal "old" is assignable to string, azureLocation is assignable to string.4. Discriminator Preservation
Section titled “4. Discriminator Preservation”Discriminator properties are never dropped, even if the new base has a same-named property.
Common Use Cases
Section titled “Common Use Cases”Multi-Level Discriminated Hierarchy
Section titled “Multi-Level Discriminated Hierarchy”Use the decorator to create deeper inheritance in discriminated models:
@discriminator("kind")model Animal { kind: string; name: string;}
alias PetContent = { trained: boolean;};
model Pet extends Animal { kind: "pet"; ...PetContent;}
alias DogContent = { breed: string;};
@Azure.ClientGenerator.Core.Legacy.hierarchyBuilding(Pet)model Dog extends Animal { kind: "dog"; ...PetContent; ...DogContent;}// SDK result: Dog extends Pet. Dog.properties = { kind, breed }.// 'trained' is supplied by Pet → dropped. 'kind' is a discriminator → preserved.Brownfield ARM Resource Rebasing
Section titled “Brownfield ARM Resource Rebasing”A common pattern for Azure resources that need to be rebased onto TrackedResource:
model Resource { id?: string; name?: string; type?: string;}model TrackedResource extends Resource { location: string; tags?: Record<string>;}model Foo extends Resource { properties: FooProperties; location?: string; tags?: Record<string>;}@@Azure.ClientGenerator.Core.Legacy.hierarchyBuilding(Foo, TrackedResource);// SDK result: Foo extends TrackedResource. Foo.properties = { properties }.// location and tags are supplied by TrackedResource → dropped.// id, name, type are supplied by Resource (in TrackedResource's chain) → dropped.