import type { O } from "ts-toolbelt";
import type { LateTypeChecker, TypeChecker } from "../typeChecking/TypeChecker";
import type { IsOptionalValue } from "../utils/types";
/**
 * @ignore
 */
export declare const noDefaultValue: unique symbol;
/**
 * A model property.
 */
export interface ModelProp<TPropValue, TPropCreationValue, TIsOptional, TIsId extends boolean = false, THasSetter = never> {
    $valueType: TPropValue;
    $creationValueType: TPropCreationValue;
    $isOptional: TIsOptional;
    $isId: TIsId;
    $hasSetter: THasSetter;
    defaultFn: (() => TPropValue) | typeof noDefaultValue;
    defaultValue: TPropValue | typeof noDefaultValue;
    typeChecker: TypeChecker | LateTypeChecker | undefined;
    setter: boolean | "assign";
    withSetter(mode?: boolean | "assign"): ModelPropWithSetter<this>;
}
/**
 * Any model property.
 */
export declare type AnyModelProp = ModelProp<any, any, any, any, any>;
/**
 * Model properties.
 */
export interface ModelProps {
    [k: string]: AnyModelProp;
}
export declare type OptionalModelProps<MP extends ModelProps> = {
    [K in keyof MP]: MP[K]["$isOptional"] & K;
}[keyof MP];
export declare type ModelPropsToData<MP extends ModelProps> = {
    [k in keyof MP]: MP[k]["$valueType"];
};
export declare type ModelPropsToCreationData<MP extends ModelProps> = {
    [k in keyof MP]?: MP[k]["$creationValueType"];
} & O.Omit<{
    [k in keyof MP]: MP[k]["$creationValueType"];
}, OptionalModelProps<MP>>;
export declare type ModelPropsToSetter<MP extends ModelProps> = {
    [k in keyof MP as MP[k]["$hasSetter"] & `set${Capitalize<k & string>}`]: (value: MP[k]["$valueType"]) => void;
};
/**
 * A property that will be used as model id, replacing $modelId.
 * Can only be used in models and there can be only one per model.
 */
export declare const idProp: ModelProp<string, string, string, true, never>;
/**
 * @ignore
 */
export declare type OnlyPrimitives<T> = Exclude<T, object>;
/**
 * A model prop that maybe / maybe not is optional, depending on if the value can take undefined.
 */
export declare type MaybeOptionalModelProp<TPropValue> = ModelProp<TPropValue, TPropValue, IsOptionalValue<TPropValue, string, never>>;
/**
 * A model prop that is definitely optional.
 */
export declare type OptionalModelProp<TPropValue> = ModelProp<TPropValue, TPropValue | null | undefined, string>;
/**
 * A model prop with a generated setter.
 */
export declare type ModelPropWithSetter<MP extends AnyModelProp> = Omit<MP, "$hasSetter"> & {
    $hasSetter: string;
};
/**
 * Defines a model property, with an optional function to generate a default value
 * if the input snapshot / model creation data is `null` or `undefined`.
 *
 * Example:
 * ```ts
 * x: prop(() => 10) // an optional number, with a default value of 10
 * x: prop<number[]>(() => []) // an optional number array, with a default empty array
 * ```
 *
 * @typeparam TValue Value type.
 * @param defaultFn Default value generator function.
 * @returns
 */
export declare function prop<TValue>(defaultFn: () => TValue): OptionalModelProp<TValue>;
/**
 * Defines a model property, with an optional default value
 * if the input snapshot / model creation data is `null` or `undefined`.
 * You should only use this with primitive values and never with object values
 * (array, model, object, etc).
 *
 * Example:
 * ```ts
 * x: prop(10) // an optional number, with a default value of 10
 * ```
 *
 * @typeparam TValue Value type.
 * @param defaultValue Default primitive value.
 * @returns
 */
export declare function prop<TValue>(defaultValue: OnlyPrimitives<TValue>): OptionalModelProp<TValue>;
/**
 * Defines a model property with no default value.
 *
 * Example:
 * ```ts
 * x: prop<number>() // a required number
 * x: prop<number | undefined>() // an optional number, which defaults to undefined
 * ```
 *
 * @typeparam TValue Value type.
 * @returns
 */
export declare function prop<TValue>(): MaybeOptionalModelProp<TValue>;
