import '../../../assert/js/assert.js';
import '../../../globals.js';
/**
 * Class responsible for storing information about the schema of PhET-iO state. See IOType stateSchema option for usage
 * and more information.
 *
 * There are two types of StateSchema:
 * - The first is a stateSchema "value". This is when the state of an IOType is itself a value in the state. In
 * effect, this just serves as boilerplate, and isn't the primary usage of stateSchema. For example, a StringIO or
 * NumberIO.
 * - The second is a "composite", where the state of an IOType is made from subcomponents, each of which have an IOType.
 * A composite schema was named because it is a sum of its parts. For example a BunnyIO has multiple components that
 * make it up (mother/father/age/etc). Check which type of StateSchema your instance is with StateSchema.isComposite().
 *
 * When stored in the API, StateSchema values are stored as strings, see StateSchema.asValue, and composite state schemas
 * are stored as objects with values that are each IOType names.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */
import { Validator } from '../../../axon/js/Validation.js';
import IOType from './IOType.js';
import IntentionalAny from '../../../phet-core/js/types/IntentionalAny.js';
import { IOTypeName } from '../TandemConstants.js';
/**
 * This is the primary functionality of the StateSchema class. An IOType can be provided a composite schema like so:
 * {
 *   subcomponent1: StringIO;
 *   subcomponent2: NumberIO;
 * }
 * By providing this, you are giving the schema to allow StateSchema to serialize and deserialize itself based on the
 * composite schema.
 */
export type CompositeSchema<SelfStateType> = {
    [K in keyof SelfStateType]: IOType;
};
export type APIStateKeys = string[];
type CompositeSchemaAPI = Record<string, IOTypeName>;
export type CompositeStateObjectType = Record<string, IntentionalAny>;
export type StateObject<T extends Record<string, IOType>> = {
    [key in keyof T]: ReturnType<T[key]['toStateObject']>;
};
type StateSchemaOptions<SelfStateType> = {
    displayString?: string;
    validator?: Validator<IntentionalAny> | null;
    compositeSchema?: null | CompositeSchema<SelfStateType>;
    apiStateKeys?: APIStateKeys | null;
};
export default class StateSchema<T, SelfStateType> {
    private readonly displayString;
    private readonly validator;
    readonly compositeSchema: null | CompositeSchema<SelfStateType>;
    readonly apiStateKeys: APIStateKeys | null;
    constructor(providedOptions?: StateSchemaOptions<SelfStateType>);
    /**
     * This method provides a default implementation for setting a stateObject onto an object from the stateSchema information.
     * It supports the coreObject keys as private, underscore-prefixed field, as
     * well as if the coreObject has an es5 setter instead of an actual field.
     */
    defaultApplyState(coreObject: T, stateObject: CompositeStateObjectType): void;
    /**
     * This method provides a default implementation for creating a stateObject from the stateSchema by accessing those
     * same key names on the coreObject instance. It supports those keys as private, underscore-prefixed field, as
     * well as if the coreObject has an es5 getter instead of an actual field.
     */
    defaultToStateObject(coreObject: T): SelfStateType;
    /**
     * Provide the member string key that should be used to get/set an instance's field. Used only internally for the
     * default implementations of toStateObject and applyState.
     */
    private getCoreObjectAccessorName;
    /**
     * True if the StateSchema is a composite schema. See the header documentation in this file for the definition
     * of "composite" schema.
     */
    isComposite(): boolean;
    /**
     * Check if a given stateObject is as valid as can be determined by this StateSchema. Will return null if valid, but
     * needs more checking up and down the hierarchy.
     *
     * @param stateObject - the stateObject to validate against
     * @param toAssert - whether to assert when invalid
     * @param schemaKeysPresentInStateObject - to be populated with any keys this StateSchema is responsible for.
     * @returns boolean if validity can be checked, null if valid, but next in the hierarchy is needed
     */
    checkStateObjectValid(stateObject: SelfStateType, toAssert: boolean, schemaKeysPresentInStateObject: string[]): boolean | null;
    /**
     * Get a list of all IOTypes associated with this StateSchema
     */
    getRelatedTypes(): IOType[];
    /**
     * Returns a unique identified for this stateSchema, or an object of the stateSchemas for each sub-component in the composite
     * (phet-io internal)
     */
    getStateSchemaAPI(): string | CompositeSchemaAPI;
    /**
     * Factory function for StateSchema instances that represent a single value of state. This is opposed to a composite
     * schema of sub-components.
     */
    static asValue<T, StateType>(displayString: string, validator: Validator<IntentionalAny>): StateSchema<T, StateType>;
}
export {};
//# sourceMappingURL=StateSchema.d.ts.map