/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import type { TreeNodeSchema, TreeNodeFromImplicitAllowedTypes, TreeFieldFromImplicitField, SchemaFactoryBeta } from "./simple-tree/index.js";
/**
 * Utilities for creating extensible unions using a node.
 * @remarks
 * Use {@link ExtensibleUnionNode.createSchema} to create the union schema.
 *
 * Unlike a schema union created using {@link SchemaStaticsBeta.staged | staged} allowed types, this union allows for unknown future types to exist in addition to the known types.
 * This allows for faster roll-outs of new types without waiting for old clients to be updated to be aware of them.
 * This does mean however that old clients may see types they do not know about, which are simply exposed as `undefined` children.
 *
 * `staged` types are lower overhead, and might gain support for `unknown` types in the future, so prefer them when possible.
 * This is simply an alternative for when future compatibility with unknown types is required.
 * It is built on top of the existing {@link ObjectSchemaOptions.allowUnknownOptionalFields | allowUnknownOptionalFields} feature.
 *
 * @example
 * ```typescript
 * const sf = new SchemaFactoryBeta("extensibleUnionNodeExample.items");
 * class ItemA extends sf.object("A", { x: sf.string }) {}
 * class ItemB extends sf.object("B", { x: sf.number }) {}
 *
 * class AnyItem extends ExtensibleUnionNode.createSchema(
 * 	[ItemA, ItemB], // Future versions may add more members here
 * 	sf,
 * 	"ExtensibleUnion",
 * ) {}
 * // Instances of the union are created using `create`.
 * const anyItem = AnyItem.create(new ItemA({ x: "hello" }));
 * // Reading the content from the union is done via the `union` property,
 * // which can be `undefined` to handle the case where a future version of this schema allows a type unknown to the current version.
 * const childNode: ItemA | ItemB | undefined = anyItem.union;
 * // To determine which member of the union was present, its schema can be inspected:
 * const aSchema = Tree.schema(childNode ?? assert.fail("No child"));
 * assert.equal(aSchema, ItemA);
 * ```
 * @beta
 */
export declare namespace ExtensibleUnionNode {
    /**
     * Members for classes created by {@link ExtensibleUnionNode.createSchema}.
     * @beta
     */
    interface Members<T> {
        /**
         * The child wrapped by this node has one of the types allowed by the union,
         * or `undefined` if the type is one which was added to the union by a future version of this schema.
         *
         * @throws if {@link ExtensibleUnionNode.Members.isValid} is false.
         */
        readonly union: T | undefined;
        /**
         * Returns true, unless this node is in an invalid state.
         * @remarks
         * A well behaved application should not need this API.
         * If an application is hitting errors when accessing {@link ExtensibleUnionNode.Members.union},
         * this API can be used to help detect and recover from the invalid state which causes those errors (for example by replacing the invalid nodes with new ones).
         *
         * In this context "invalid" means that the internal implementation details of this node have had their invariants violated.
         * This can happen when:
         * - Using weakly typed construction APIs like {@link (TreeBeta:interface).importConcise} or {@link (TreeAlpha:interface).importVerbose} to construct an invalid state directly.
         * Using such APIs, even when not creating invalid nodes, is not supported for this schema,
         * since doing so requires knowing the implementation details of this node which are subject to change.
         * - By editing a document using a different client using a different schema for this node.
         * - Violating the TypeScript types to directly manipulate the node internals.
         * - A bug in this node's implementation (possibly in a different client) corrupted the node.
         * - Corruption of the document this node is contained in.
         *
         * @privateRemarks
         * We could support {@link (TreeBeta:interface).exportVerbose} using {@link KeyEncodingOptions.allStoredKeys}
         * then {@link (TreeAlpha:interface).importVerbose} with {@link KeyEncodingOptions.knownStoredKeys}.
         * However, even this will error (but will not produce an invalid node) if there is a node of an unknown type in the union.
         */
        isValid(): boolean;
    }
    /**
     * Statics for classes created by {@link ExtensibleUnionNode.createSchema}.
     * @beta
     */
    interface Statics<T extends readonly TreeNodeSchema[]> {
        /**
         * Create a {@link TreeNode} with `this` schema which wraps the provided child to create the union.
         */
        create<TThis extends TreeNodeSchema>(this: TThis, child: TreeNodeFromImplicitAllowedTypes<T>): TreeFieldFromImplicitField<TThis>;
    }
    /**
     * Create an extensible schema union which currently supports the types in `types`,
     * but tolerates collaboration with future versions that may include additional types.
     * @remarks
     * See {@link ExtensibleUnionNode} for an example use.
     * @beta
     */
    function createSchema<const T extends readonly TreeNodeSchema[], const TScope extends string, const TName extends string>(types: T, inputSchemaFactory: SchemaFactoryBeta<TScope>, name: TName): Statics<T> & import("./simple-tree/index.js").TreeNodeSchemaCore<import("./simple-tree/index.js").ScopedSchemaName<`com.fluidframework.extensibleUnionNode<${TScope}>`, TName>, import("./simple-tree/index.js").NodeKind, false, unknown, never, unknown> & (new (data: import("./simple-tree/index.js").InternalTreeNode) => Members<TreeNodeFromImplicitAllowedTypes<T>> & import("./simple-tree/index.js").TreeNode & import("./simple-tree/index.js").WithType<import("./simple-tree/index.js").ScopedSchemaName<`com.fluidframework.extensibleUnionNode<${TScope}>`, TName>, import("./simple-tree/index.js").NodeKind, unknown>);
}
//# sourceMappingURL=extensibleUnionNode.d.ts.map