import { NeverType } from './never.type';
import { NumberType } from './number.type';
import { Equal, ObjectType } from './object.type';
import { Primitive, ReadonlyOrNot } from './primitive.type';
export declare namespace ArrayType {
    export type TypePredicate<Container extends ReadonlyOrNot<any[]>, Target> = {
        <Index extends number, __Target extends Target = Target>(value?: ArrayType.At<Container, Index>, index?: Index, array?: Container): value is Target;
    };
    /**
     * @todo don't use `Equal` type and use `includes` of `union types` ( make `union incldues` type )
     */
    export type Filter<T extends ReadonlyOrNot<any[]>, Target> = T extends [infer First, ...infer Rest] ? Equal<First, Target> extends true ? [First, ...Filter<Rest, Target>] : Filter<Rest, Target> : [];
    type _FilterNull<FilterNull extends boolean, Target> = FilterNull extends true ? Equal<Target, null> extends true ? never : Target : Target;
    type _FilterUndefined<FilterUndefined extends boolean, Target> = FilterUndefined extends true ? Equal<Target, undefined> extends true ? never : Target : Target;
    /**
     * type a = ArrayType.Filter<[1, 2, true, 3, undefined, null, 5], true, true> // [1, 2, 3, 5]
     */
    export type FilterNullish<T extends ReadonlyOrNot<any[]>, AllowNull extends boolean, AllowUndefined extends boolean> = IsTuple<T> extends false ? Exclude<ElementOf<T>, (AllowNull extends true ? null : never) | (AllowUndefined extends true ? undefined : never)>[] : T extends [infer First, ...infer Rest] ? NeverType.IsNever<_FilterNull<AllowNull, First>> extends true ? FilterNullish<Rest, AllowNull, AllowUndefined> : NeverType.IsNever<_FilterUndefined<AllowUndefined, First>> extends true ? FilterNullish<Rest, AllowNull, AllowUndefined> : [First, ...FilterNullish<Rest, AllowNull, AllowUndefined>] : [];
    /**
     * Get length of tuple or string literal type.
     */
    export type Length<T extends ReadonlyOrNot<any[]>> = T['length'];
    export type Push<T extends ReadonlyOrNot<any[]>, V extends any> = [...T, V];
    export type Concat<T extends ReadonlyOrNot<any[]>, P extends ReadonlyOrNot<any[]>> = [...T, ...P];
    export type ElementOf<Tuple extends ReadonlyOrNot<any[]>> = [...Tuple] extends (infer E)[] ? E : never;
    export type Values<T extends ReadonlyOrNot<any[]>> = T[number];
    export type TupleToUnion<T extends NTuple<number>> = T[number];
    export type Take<T extends ReadonlyOrNot<any[]>, P extends number, R extends ReadonlyOrNot<any[]> = []> = ArrayType.Length<R> extends P ? R : T extends [infer F, ...infer Rest] ? Take<Rest, P, ArrayType.Push<R, F>> : R;
    export type Slice<T extends ReadonlyOrNot<any[]>, Start extends number, End extends number> = SliceByValue<T, T[Start], NeverType.IsNever<End> extends true ? never : T[End]>;
    /**
     * Returns matching A to matching B in tuple form.
     * If there are no elements that match A or B, then never type.
     */
    export type SliceByValue<T extends ReadonlyOrNot<any[]>, A extends any, B extends any, CONDITION extends boolean = false> = T extends [infer X, ...infer Rest] ? CONDITION extends true ? X extends B ? [X, ...SliceByValue<Rest, A, B, false>] : [X, ...SliceByValue<Rest, A, B, true>] : X extends A ? X extends B ? [X, ...SliceByValue<Rest, A, B, false>] : [X, ...SliceByValue<Rest, A, B, true>] : SliceByValue<Rest, A, B, false> : CONDITION extends true ? [] : [];
    export type At<Tuple extends ReadonlyOrNot<any[]>, Index extends number> = Tuple[Index];
    /**
     * If any of the type elements constituting Union Type U correspond to `If`, it returns true or false.
     */
    export type UnionSome<If, U, T, F> = T extends (U extends If ? T : F) ? T : F;
    /**
     * If any of the type elements constituting Tuple Type U correspond to `If`, it returns true or false.
     */
    export type Some<Target, Tuple extends ReadonlyOrNot<any[]>> = UnionSome<Target, Tuple[number], true, false> | boolean;
    export type Includes<T extends ReadonlyOrNot<any[]>, U> = T extends [infer P, ...infer R] ? Equal<U, P> extends true ? true : Includes<R, U> : false;
    /**
     * Join<['a', 'b', 'c']> // 'abc'
     * Join<['a', 'b', 'c'], '-'> // 'a-b-c'
     * Join<string[], "-">; // string
     * Join<['a', 'b', 'c', true], '-'>; // 'a-b-c-true'
     * Join<['a', 'b', 'c', number], '-'>; // 'a-b-c-${number}'
     */
    export type Join<T extends ReadonlyOrNot<Exclude<Primitive, symbol>[]>, U extends string = ','> = T extends readonly [
        infer F extends Exclude<Primitive, symbol>,
        ...infer Rest extends ReadonlyOrNot<Exclude<Primitive, symbol>[]>
    ] ? Rest extends [] ? `${F}` : `${F}${U}${Join<Rest, U>}` : string;
    export type IsTuple<T extends ReadonlyOrNot<any[]> | {
        length: number;
    }> = [T] extends [never] ? false : T extends ReadonlyOrNot<any[]> ? number extends T['length'] ? false : true : false;
    /**
     * Reverse<[1,2,3]> // [3,2,1]
     */
    export type Reverse<T extends ReadonlyOrNot<any[]>> = T extends [infer F, ...infer Rest] ? [...Reverse<Rest>, F] : [];
    /**
     * Shift<[1,2,3]> // [2,3]
     */
    export type Shift<T extends ReadonlyOrNot<any[]>, N extends number> = T extends [
        ...infer F extends NTuple<N>,
        ...infer Rest
    ] ? Rest : [];
    /**
     * Unshift<[1, 2, 3], 4> // [4,1,2,3]
     */
    export type Unshift<T extends ReadonlyOrNot<any[]>, V> = [V, ...T];
    /**
     * Pop<[1,2,3]> // [1,2]
     */
    export type Pop<T extends ReadonlyOrNot<any[]>> = T extends [...infer Rest, infer Last] ? Rest : [];
    /**
     * 튜플에서 중복 요소를 제거하는 타입
     *
     * Distinct<[1,1,2,2,3,3,3,4]> // [1,2,3,4]
     */
    export type Distinct<T extends ReadonlyOrNot<any[]>, P extends ReadonlyOrNot<any[]> = []> = T extends [
        infer F,
        ...infer Rest
    ] ? Includes<P, F> extends false ? Distinct<Rest, [...P, F]> : Distinct<Rest, P> : P;
    export type EntriesToObject<T extends Array<NTuple<2>>> = T extends [infer F, ...infer Rest] ? F extends [infer K extends string, infer V] ? Rest extends NTuple<2>[] ? ObjectType.Merge<Record<K, V>, EntriesToObject<Rest>> : never : never : {};
    /**
     * PartitionByTwo<[1,2,3,4,5,6,7,8]> // [[1,2],[3,4],[5,6],[7,8]]
     */
    export type PartitionByTwo<T extends ReadonlyOrNot<any[]>, L extends number = ArrayType.Length<T>> = T extends [
        infer First,
        infer Second,
        ...infer Rest
    ] ? [[First, Second], ...PartitionByTwo<Rest, NumberType.Sub<L, 2>>] : [];
    export type BubbleSort<T extends ReadonlyOrNot<any[]>, L extends number = ArrayType.Length<T>> = L extends 1 ? T : T extends [infer F, infer S, ...infer Rest] ? BubbleSort<[
        ...(NumberType.Compare<NumberType.NToNumber<F>, '>=', NumberType.NToNumber<S>> extends false ? [F, ...BubbleSort<[S, ...Rest], NumberType.Sub<L, 1>>] : [S, ...BubbleSort<[F, ...Rest], NumberType.Sub<L, 1>>])
    ], NumberType.Sub<L, 1>> : never;
    /**
     * 사칙연산을 튜플에 적용한 타입
     *
     * type a = Map<[3, 4, 5], "Add", 2>; // [5, 6, 7]
     * type b = Map<[3, 4, 5], "Multiply", 2>; // [6, 8, 10]
     * type c = Map<[3, 4, 5], "Sub", 2>; // [1, 2, 3]
     * type d = Map<[3, 4, 5], "Divide", 2>; // [1, 2, 2]
     * type e = Map<[3, 4, 5], "Remainder", 2>; // [1, 0, 1]
     */
    export type Map<T extends readonly number[], OP extends 'Add' | 'Multiply' | 'Sub' | 'Divide' | 'Remainder', N extends number> = OP extends 'Add' ? {
        [K in keyof T]: NumberType.Add<T[K], N>;
    } : OP extends 'Multiply' ? {
        [K in keyof T]: NumberType.Multiply<T[K], N>;
    } : OP extends 'Sub' ? {
        [K in keyof T]: NumberType.Sub<T[K], N>;
    } : OP extends 'Divide' ? {
        [K in keyof T]: NumberType.Divide<T[K], N>;
    } : OP extends 'Remainder' ? {
        [K in keyof T]: NumberType.Remainder<T[K], N>;
    } : never;
    export {};
}
/**
 * 현재 튜플 형태에 새로운 타입 하나를 추가하는 타입
 *
 * Push<[], any> // [any]
 * Push<[], 1> // [1]
 */
export type NTuple<N extends number, T extends ReadonlyOrNot<any[]> = [], defaultType = any> = T['length'] extends N ? T : NTuple<N, ArrayType.Push<T, defaultType>>;
/**
 * N1 * N2 크기의 NTuple을 반환하는 타입으로, 최적화를 위해 N1, N2 숫자를 비교하는 과정이 포함된 타입
 *
 * NNTuple<2,3> = [...NTuple<3>, ...NTuple<3>]
 * NNTuple<3,2> = [...NTuple<3>, ...NTuple<3>]
 */
export type NNTuple<N1 extends number, N2 extends number> = [NumberType.Sub<N1, N2>] extends [never] ? NumberType.Sub<N1, 1> extends never ? [] : [...NNTuple<NumberType.Sub<N1, 1>, N2>, ...NTuple<N2>] : NumberType.Sub<N2, 1> extends never ? [] : [...NNTuple<NumberType.Sub<N2, 1>, N1>, ...NTuple<N1>];
//# sourceMappingURL=array.type.d.ts.map