import { IValidationContext, IValidationResult, IStateTreeNode, ModelPrimitive } from "../../internal";
import type { WritableKeys } from "ts-essentials";
/**
 * A state tree node value.
 * @hidden
 */
export type STNValue<T, IT extends IAnyType> = T extends object ? T & IStateTreeNode<IT> : T;
/** @hidden */
declare const $type: unique symbol;
type ExcludeReadonly<T> = T extends {} ? T[WritableKeys<T>] : T;
/**
 * A type, either complex or simple.
 */
export interface IType<C, S, T> {
    /** @hidden */
    readonly [$type]: undefined;
    /**
     * Friendly type name.
     */
    name: string;
    /**
     * Name of the identifier attribute or null if none.
     */
    readonly identifierAttribute?: string;
    /**
     * Creates an instance for the type given an snapshot input.
     *
     * @returns An instance of that type.
     */
    create(snapshot?: C | ExcludeReadonly<T>, env?: any): this["Type"];
    /**
     * Checks if a given snapshot / instance is of the given type.
     *
     * @param thing Snapshot or instance to be checked.
     * @returns true if the value is of the current type, false otherwise.
     */
    is(thing: any): thing is C | this["Type"];
    /**
     * Run's the type's typechecker on the given value with the given validation context.
     *
     * @param thing Value to be checked, either a snapshot or an instance.
     * @param context Validation context, an array of { subpaths, subtypes } that should be validated
     * @returns The validation result, an array with the list of validation errors.
     */
    validate(thing: C | T, context: IValidationContext): IValidationResult;
    /**
     * Gets the textual representation of the type as a string.
     */
    describe(): string;
    /**
     * @deprecated use `Instance<typeof MyType>` instead.
     * @hidden
     */
    readonly Type: STNValue<T, this>;
    /**
     * @deprecated do not use.
     * @hidden
     */
    readonly TypeWithoutSTN: T;
    /**
     * @deprecated use `SnapshotOut<typeof MyType>` instead.
     * @hidden
     */
    readonly SnapshotType: S;
    /**
     * @deprecated use `SnapshotIn<typeof MyType>` instead.
     * @hidden
     */
    readonly CreationType: C;
}
/**
 * Any kind of type.
 */
export interface IAnyType extends IType<any, any, any> {
}
/**
 * A simple type, this is, a type where the instance and the snapshot representation are the same.
 */
export interface ISimpleType<T> extends IType<T, T, T> {
}
/** @hidden */
export type Primitives = ModelPrimitive | null | undefined;
/**
 * A complex type.
 * @deprecated just for compatibility with old versions, could be deprecated on the next major version
 * @hidden
 */
export interface IComplexType<C, S, T> extends IType<C, S, T & object> {
}
/**
 * Any kind of complex type.
 */
export interface IAnyComplexType extends IType<any, any, object> {
}
/** @hidden */
export type ExtractCSTWithoutSTN<IT extends {
    [$type]: undefined;
    CreationType: any;
    SnapshotType: any;
    TypeWithoutSTN: any;
}> = IT["CreationType"] | IT["SnapshotType"] | IT["TypeWithoutSTN"];
/** @hidden */
export type ExtractCSTWithSTN<IT extends {
    [$type]: undefined;
    CreationType: any;
    SnapshotType: any;
    Type: any;
}> = IT["CreationType"] | IT["SnapshotType"] | IT["Type"];
/**
 * The instance representation of a given type.
 */
export type Instance<T> = T extends {
    [$type]: undefined;
    Type: any;
} ? T["Type"] : T;
/**
 * The input (creation) snapshot representation of a given type.
 */
export type SnapshotIn<T> = T extends {
    [$type]: undefined;
    CreationType: any;
} ? T["CreationType"] : T extends IStateTreeNode<infer IT> ? IT["CreationType"] : T;
/**
 * The output snapshot representation of a given type.
 */
export type SnapshotOut<T> = T extends {
    [$type]: undefined;
    SnapshotType: any;
} ? T["SnapshotType"] : T extends IStateTreeNode<infer IT> ? IT["SnapshotType"] : T;
/**
 * A type which is equivalent to the union of SnapshotIn and Instance types of a given typeof TYPE or typeof VARIABLE.
 * For primitives it defaults to the primitive itself.
 *
 * For example:
 * - `SnapshotOrInstance<typeof ModelA> = SnapshotIn<typeof ModelA> | Instance<typeof ModelA>`
 * - `SnapshotOrInstance<typeof self.a (where self.a is a ModelA)> = SnapshotIn<typeof ModelA> | Instance<typeof ModelA>`
 *
 * Usually you might want to use this when your model has a setter action that sets a property.
 *
 * Example:
 * ```ts
 * const ModelA = types.model({
 *   n: types.number
 * })
 *
 * const ModelB = types.model({
 *   innerModel: ModelA
 * }).actions(self => ({
 *   // this will accept as property both the snapshot and the instance, whichever is preferred
 *   setInnerModel(m: SnapshotOrInstance<typeof self.innerModel>) {
 *     self.innerModel = cast(m)
 *   }
 * }))
 * ```
 */
export type SnapshotOrInstance<T> = SnapshotIn<T> | Instance<T>;
/**
 * Returns if a given value represents a type.
 *
 * @param value Value to check.
 * @returns `true` if the value is a type.
 */
export declare function isType(value: any): value is IAnyType;
export {};
