/**
 * @since 0.1.0
 */
import * as Sum from "@unsplash/sum-types";
import * as t from "io-ts";
import * as O from "fp-ts/Option";
declare type Tag<A> = A extends Sum.Member<infer B, any> ? B : never;
declare type Value<A> = A extends Sum.Member<any, infer B> ? B : never;
declare type NullaryMember = Sum.Member<string>;
declare type Primitive = string | number | boolean | bigint | undefined | null;
/**
 * Ensures that every key in union `A` is present at least once in array `B`.
 *
 * @link https://github.com/Microsoft/TypeScript/issues/13298#issuecomment-468733257
 */
declare type EveryKeyPresent<A, B> = Array<A> extends B ? B extends Array<A> ? B : never : never;
/**
 * An object from member tags to codecs of their values.
 *
 * We require codecs for members without values as well as needing all of the
 * keys to be present at runtime.
 *
 * `B` exists to support constraints on encoded representations.
 */
declare type MemberCodecs<A extends Sum.AnyMember, B = unknown> = {
    readonly [C in A as Tag<C>]: t.Type<Value<C>, B>;
};
declare type OutputsOf<A extends Sum.AnyMember, B extends MemberCodecs<A>> = A extends Sum.AnyMember ? Sum.Member<Tag<A>, B[Tag<A>] extends t.Type<any, infer C> ? C : never> : never;
/**
 * Derive a codec for nullary members to/from any other type. If the encoded
 * representation forms part of an object then `nullaryFromEmpty` can be used
 * instead. Incompatible with `Serialized` if not encoding to `null`.
 *
 * @example
 * import * as t from "io-ts"
 * import { nullaryFrom } from "@unsplash/sum-types-io-ts"
 *
 * // This will decode any object to null and encode to an empty object. Instead
 * // consider `nullaryFromEmpty`.
 * nullaryFrom({})(t.type({}))
 *
 * @since 0.7.0
 */
export declare const nullaryFrom: <A>(to: A) => (from: t.Type<A, unknown, unknown>) => t.Type<null, A, unknown>;
/**
 * A representation of nullary member values that encodes to `undefined` for
 * better JSON interop, and decodes from `undefined`, `null`, or empty objects
 * (i.e. any object). Incompatible with `Serialized`.
 *
 * @since 0.7.0
 */
export declare const nullaryFromEmpty: t.Type<null, undefined | null | Record<string, unknown>>;
/**
 * Derive a codec for `Serialized<A>` for any given sum `A` provided codecs for
 * all its members` values.
 *
 * @since 0.1.0
 */
export declare const getSerializedCodec: <A extends Sum.AnyMember>() => <B extends MemberCodecs<A, unknown>>(cs: B, name?: string) => t.Type<Sum.Serialized<A>, Sum.Serialized<OutputsOf<A, B>>, unknown>;
/**
 * Derive a codec for any given sum `A` provided codecs for all its members'
 * values, decoding and encoding to/from `Serialized<A>`.
 *
 * @since 0.1.0
 */
export declare const getCodecFromSerialized: <A extends Sum.AnyMember>(sum: Sum.Sum<A>) => <B extends MemberCodecs<A, unknown>>(cs: B, name?: string) => t.Type<A, Sum.Serialized<OutputsOf<A, B>>, unknown>;
/**
 * Derive a codec for any given sum `A` provided codecs for all its members'
 * values.
 *
 * @since 0.1.0
 */
export declare const getCodec: <A extends Sum.AnyMember>(sum: Sum.Sum<A>) => <B extends MemberCodecs<A, unknown>>(cs: B, name?: string) => t.Type<A, OutputsOf<A, B>, unknown>;
/**
 * Derive a codec for any given sum `A` in which all the constructors are
 * nullary, decoding and encoding to/from the constructor tags via conversion
 * functions. Consider instead `getCodecFromPrimitiveMappedNullaryTag` for
 * stringly APIs.
 *
 * @example
 * import * as t from "io-ts"
 * import * as Sum from "@unsplash/sum-types"
 * import { getCodecFromMappedNullaryTag } from "@unsplash/sum-types-io-ts"
 * import * as O from "fp-ts/Option"
 * import * as E from "fp-ts/Either"
 *
 * type Weather = Sum.Member<"Sun"> | Sum.Member<"Rain">
 * const Weather = Sum.create<Weather>()
 * type Country = "UK" | "Italy"
 *
 * const WeatherFromCountry: t.Type<Weather, Country> =
 *   getCodecFromMappedNullaryTag(Weather)(
 *     x => {
 *       switch (x) {
 *         case "Italy":
 *           return O.some("Sun")
 *         case "UK":
 *           return O.some("Rain")
 *         default:
 *           return O.none
 *       }
 *     },
 *     (x): Country => (x === "Sun" ? "Italy" : "UK"),
 *   )(["Sun", "Rain"])
 *
 * assert.deepStrictEqual(WeatherFromCountry.decode("UK"), E.right(Weather.mk.Rain))
 *
 * @since 0.3.0
 */
export declare const getCodecFromMappedNullaryTag: <A extends NullaryMember>(sum: Sum.Sum<A>) => <O, I>(from: (x: I) => O.Option<Tag<A>>, to: (x: Tag<A>) => O) => <C>(tags: EveryKeyPresent<Tag<A>, C>, name?: string) => t.Type<A, O, I>;
/**
 * @since 0.5.1
 */
export declare class MappedType<A, B> extends t.Type<A, B, unknown> {
    readonly Map: Record<Tag<A>, B>;
    /**
     * @since 0.5.1
     */
    readonly _tag: "@unsplash/sum-types-io-ts/MappedType";
    constructor(name: string, is: MappedType<A, B>["is"], validate: MappedType<A, B>["validate"], encode: MappedType<A, B>["encode"], Map: Record<Tag<A>, B>);
}
/**
 * A convenient alternative to `getCodecFromMappedNullaryTag` for working with
 * for example stringly APIs. The behaviour is unspecified if the input `Record`
 * contains duplicate values.
 *
 * @example
 * import * as t from "io-ts"
 * import * as Sum from "@unsplash/sum-types"
 * import { getCodecFromPrimitiveMappedNullaryTag } from "@unsplash/sum-types-io-ts"
 * import * as E from "fp-ts/Either"
 *
 * type Weather = Sum.Member<"Sun"> | Sum.Member<"Rain">
 * const Weather = Sum.create<Weather>()
 * type Country = "UK" | "Italy"
 *
 * const WeatherFromCountry: t.Type<Weather, Country> =
 *   getCodecFromPrimitiveMappedNullaryTag(Weather)({ Sun: "Italy", Rain: "UK" })
 *
 * assert.deepStrictEqual(WeatherFromCountry.decode("UK"), E.right(Weather.mk.Rain))
 *
 * @since 0.5.0
 */
export declare const getCodecFromPrimitiveMappedNullaryTag: <A extends NullaryMember>(sum: Sum.Sum<A>) => <B extends Primitive>(tos: Record<Tag<A>, B>, name?: string) => MappedType<A, B>;
/**
 * Derive a codec for any given sum `A` in which all the constructors are
 * nullary, decoding and encoding to/from the constructor tags.
 *
 * @since 0.3.0
 */
export declare const getCodecFromNullaryTag: <A extends NullaryMember>(sum: Sum.Sum<A>) => <B>(tags: EveryKeyPresent<Tag<A>, B>, name?: string) => t.Type<A, string, unknown>;
/**
 * Supports any encoded representation of nullary member values.
 *
 * @example
 * ExternallyTagged<Weather, ...> = { Sun: null } | { Rain: { mm: number } }
 */
declare type ExternallyTagged<A extends Sum.AnyMember, B extends MemberCodecs<A>> = A extends Sum.AnyMember ? Record<Tag<A>, B[Tag<A>] extends t.Type<any, infer C> ? C : never> : never;
/**
 * Derive a codec for any given sum `A` provided codecs for all its members'
 * values, decoding and encoding to an object tagged by the sum member tag.
 *
 * Should the types overlap, the first valid codec will succeed.
 *
 * @example
 * import * as t from "io-ts"
 * import * as Sum from "@unsplash/sum-types"
 * import { nullaryFromEmpty, getExternallyTaggedCodec } from "@unsplash/sum-types-io-ts"
 * import * as E from "fp-ts/Either"
 *
 * type Weather = Sum.Member<"Sun"> | Sum.Member<"Rain", number>
 * const Weather = Sum.create<Weather>()
 *
 * const WeatherCodec = getExternallyTaggedCodec(Weather)({
 *   Sun: nullaryFromEmpty,
 *   Rain: t.number,
 * })
 *
 * assert.deepStrictEqual(
 *   WeatherCodec.decode({ Sun: undefined }),
 *   E.right(Weather.mk.Sun),
 * )
 *
 * assert.deepStrictEqual(
 *   WeatherCodec.decode({ Rain: 123 }),
 *   E.right(Weather.mk.Rain(123)),
 * )
 *
 * @since 0.7.0
 */
export declare const getExternallyTaggedCodec: <A extends Sum.AnyMember>(sum: Sum.Sum<A>) => <C extends MemberCodecs<A, unknown>>(cs: C, name?: string) => t.Type<A, ExternallyTagged<A, C>, unknown>;
/**
 * Supports any encoded representation of nullary member values.
 *
 * @example
 * AdjacentlyTagged<"k", "v", Weather, ...> = { k: Sun; v: null } | { k: Rain; v: { mm: number } }
 */
declare type AdjacentlyTagged<K extends string, V extends string, A extends Sum.AnyMember, B extends MemberCodecs<A>> = A extends Sum.AnyMember ? Record<K, Tag<A>> & Record<V, B[Tag<A>] extends t.Type<any, infer C> ? C : never> : never;
/**
 * Derive a codec for any given sum `A` provided codecs for all its members'
 * values, decoding and encoding to an object with sibling member tags and
 * values.
 *
 * Due to the distinct, isolated member tag, it's not possible for overlaps to
 * occur.
 *
 * @example
 * import * as t from "io-ts"
 * import * as Sum from "@unsplash/sum-types"
 * import { nullaryFromEmpty, getAdjacentlyTaggedCodec } from "@unsplash/sum-types-io-ts"
 * import * as E from "fp-ts/Either"
 *
 * type Weather = Sum.Member<"Sun"> | Sum.Member<"Rain", number>
 * const Weather = Sum.create<Weather>()
 *
 * const WeatherCodec = getAdjacentlyTaggedCodec("tag")("value")(Weather)({
 *   Sun: nullaryFromEmpty,
 *   Rain: t.number,
 * })
 *
 * assert.deepStrictEqual(
 *   WeatherCodec.decode({ tag: "Sun" }),
 *   E.right(Weather.mk.Sun),
 * )
 *
 * assert.deepStrictEqual(
 *   WeatherCodec.decode({ tag: "Rain", value: 123 }),
 *   E.right(Weather.mk.Rain(123)),
 * )
 *
 * @since 0.7.0
 */
export declare const getAdjacentlyTaggedCodec: <K extends string>(tagKey: K) => <V extends string>(valueKey: V) => <A extends Sum.AnyMember>(sum: Sum.Sum<A>) => <C extends MemberCodecs<A, unknown>>(cs: C, name?: string) => t.Type<A, AdjacentlyTagged<K, V, A, C>, unknown>;
/**
 * Supports any encoded representation of nullary member values.
 *
 * @example
 * Untagged<Weather, ...> = {} | { mm: number }
 */
declare type Untagged<A extends Sum.AnyMember, B extends MemberCodecs<A>> = A extends Sum.AnyMember ? B[Tag<A>] extends t.Type<any, infer C> ? C : never : never;
/**
 * Derive a codec for any given sum `A` provided codecs for all its members'
 * values, decoding and encoding directly to/from the member codecs.
 *
 * Should the types overlap, the first valid codec will succeed.
 *
 * @example
 * import * as t from "io-ts"
 * import * as Sum from "@unsplash/sum-types"
 * import { nullaryFromEmpty, getUntaggedCodec } from "@unsplash/sum-types-io-ts"
 * import * as E from "fp-ts/Either"
 *
 * type Weather = Sum.Member<"Sun"> | Sum.Member<"Rain", { mm: number }>
 * const Weather = Sum.create<Weather>()
 *
 * const WeatherFromRainfall = getUntaggedCodec(Weather)({
 *   Rain: t.strict({ mm: t.number }),
 *   // This codec will match any object so it needs to come last.
 *   Sun: nullaryFromEmpty,
 * })
 *
 * assert.deepStrictEqual(
 *   WeatherFromRainfall.decode({ mm: 123, foo: 'bar' }),
 *   E.right(Weather.mk.Rain({ mm: 123 })),
 * )
 *
 * assert.deepStrictEqual(
 *   WeatherFromRainfall.decode({ foo: 'bar' }),
 *   E.right(Weather.mk.Sun),
 * )
 *
 * @since 0.7.0
 */
export declare const getUntaggedCodec: <A extends Sum.AnyMember>(sum: Sum.Sum<A>) => <C extends MemberCodecs<A, unknown>>(cs: C, name?: string) => t.Type<A, Untagged<A, C>, unknown>;
/**
 * Supports only empty objects as the encoded representation of nullary member
 * values.
 *
 * @example
 * InternallyTagged<"k", Weather, ...> = { k: Sun } | { k: Rain; mm: number }
 */
declare type InternallyTagged<K extends string, A extends Sum.AnyMember, B extends MemberCodecs<A>> = A extends Sum.AnyMember ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
Record<K, Tag<A>> & (B[Tag<A>] extends t.Type<any, infer C> ? C : never) : never;
/**
 * Derive a codec for any given sum `A` provided codecs for all its members'
 * values, decoding and encoding to an object with sibling member tags and
 * values.
 *
 * Due to the distinct, isolated member tag, it's not possible for overlaps to
 * occur.
 *
 * @example
 * import * as t from "io-ts"
 * import * as Sum from "@unsplash/sum-types"
 * import { nullaryFromEmpty, getInternallyTaggedCodec } from "@unsplash/sum-types-io-ts"
 * import * as E from "fp-ts/Either"
 *
 * type Weather = Sum.Member<"Sun"> | Sum.Member<"Rain", { mm: number }>
 * const Weather = Sum.create<Weather>()
 *
 * const WeatherCodec = getInternallyTaggedCodec("tag")(Weather)({
 *   Sun: nullaryFromEmpty,
 *   Rain: t.strict({ mm: t.number }),
 * })
 *
 * assert.deepStrictEqual(
 *   WeatherCodec.decode({ tag: "Sun" }),
 *   E.right(Weather.mk.Sun),
 * )
 *
 * assert.deepStrictEqual(
 *   WeatherCodec.decode({ tag: "Rain", mm: 123 }),
 *   E.right(Weather.mk.Rain({ mm: 123 })),
 * )
 *
 * @since 0.7.0
 */
export declare const getInternallyTaggedCodec: <K extends string>(tagKey: K) => <A extends Sum.AnyMember>(sum: Sum.Sum<A>) => <C extends MemberCodecs<A, Record<string, unknown> | null | undefined>>(cs: C, name?: string) => t.Type<A, InternallyTagged<K, A, C>, unknown>;
export {};
//# sourceMappingURL=index.d.ts.map