@tsed/schema
Version:
JsonSchema module for Ts.ED Framework
132 lines (131 loc) • 3.42 kB
JavaScript
import { useDecorators } from "@tsed/core";
import { JsonEntityFn } from "./jsonEntityFn.js";
import { Property } from "./property.js";
/**
* Marks a property as the discriminator key for polymorphic type resolution.
*
* The `@DiscriminatorKey()` decorator identifies which property in a base class should
* be used to determine the concrete type in inheritance hierarchies. This is essential
* for proper serialization/deserialization of polymorphic objects and for generating
* accurate OpenAPI schemas with discriminators.
*
* ### Basic Usage
*
* ```typescript
* abstract class Animal {
* @DiscriminatorKey()
* type: string;
*
* @Property()
* name: string;
* }
*
* @DiscriminatorValue("dog")
* class Dog extends Animal {
* @Property()
* breed: string;
* }
*
* @DiscriminatorValue("cat")
* class Cat extends Animal {
* @Property()
* indoor: boolean;
* }
* ```
*
* ### How It Works
*
* When deserializing, the framework:
* 1. Reads the discriminator key property value
* 2. Maps it to the correct concrete class using `@DiscriminatorValue()`
* 3. Instantiates and validates the appropriate subclass
*
* ### With API Endpoints
*
* ```typescript
* @Controller("/animals")
* class AnimalController {
* @Post("/")
* async create(@BodyParams() animal: Animal) {
* // animal is automatically deserialized to Dog or Cat
* // based on the 'type' field in the request body
* }
* }
* ```
*
* ### OpenAPI Generation
*
* Generates discriminator object in OpenAPI spec:
*
* ```json
* {
* "discriminator": {
* "propertyName": "type",
* "mapping": {
* "dog": "#/components/schemas/Dog",
* "cat": "#/components/schemas/Cat"
* }
* }
* }
* ```
*
* ### Payment Method Example
*
* ```typescript
* abstract class PaymentMethod {
* @DiscriminatorKey()
* method: string;
* }
*
* @DiscriminatorValue("credit_card")
* class CreditCard extends PaymentMethod {
* @Property()
* cardNumber: string;
*
* @Property()
* expiryDate: string;
* }
*
* @DiscriminatorValue("bank_transfer")
* class BankTransfer extends PaymentMethod {
* @Property()
* iban: string;
*
* @Property()
* bic: string;
* }
* ```
*
* ### Use Cases
*
* - **Polymorphic APIs**: Endpoints accepting multiple related types
* - **Event Systems**: Different event types with shared base structure
* - **Strategy Pattern**: Multiple implementation variants
* - **Type-Safe Deserialization**: Automatic instantiation of correct subclass
* - **OpenAPI Documentation**: Clear polymorphic type documentation
*
* ### Best Practices
*
* - Use on abstract base classes
* - Discriminator property should be required
* - Combine with `@DiscriminatorValue()` on subclasses
* - Use meaningful, stable discriminator values
* - Document discriminator values in API documentation
*
* ### Important Notes
*
* - Only one discriminator key per class hierarchy
* - The property is automatically marked with `@Property()`
* - All subclasses must have distinct `@DiscriminatorValue()` decorators
* - Discriminator values should be unique within the hierarchy
*
* @decorator
* @property
* @public
* @see DiscriminatorValue
*/
export function DiscriminatorKey() {
return useDecorators(Property(), JsonEntityFn((store) => {
store.parent.schema.discriminatorKey(String(store.propertyKey));
}));
}