type Primitive = string | number | boolean | bigint | symbol | undefined | null;
type Builtin = Primitive | Function | Date | Error | RegExp;
type DeepReadonly<T> = T extends Builtin ? T : T extends AbstractConstructor<unknown> | ((...args: any[]) => unknown) ? T : T extends ReadonlyMap<infer K, infer V> ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>> : T extends ReadonlySet<infer U> ? ReadonlySet<DeepReadonly<U>> : T extends readonly [] | readonly [...never[]] ? readonly [] : T extends readonly [infer U, ...infer V] ? readonly [DeepReadonly<U>, ...DeepReadonly<V>] : T extends readonly [...infer U, infer V] ? readonly [...DeepReadonly<U>, DeepReadonly<V>] : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepReadonly<U>> : T extends object ? {
    readonly [K in keyof T]: DeepReadonly<T[K]>;
} : unknown;
type DeepRequired<T> = T extends Builtin ? NonNullable<T> : T extends Map<infer K, infer V> ? Map<DeepRequired<K>, DeepRequired<V>> : T extends ReadonlyMap<infer K, infer V> ? ReadonlyMap<DeepRequired<K>, DeepRequired<V>> : T extends WeakMap<infer K, infer V> ? WeakMap<DeepRequired<K>, DeepRequired<V>> : T extends Set<infer U> ? Set<DeepRequired<U>> : T extends ReadonlySet<infer U> ? ReadonlySet<DeepRequired<U>> : T extends WeakSet<infer U> ? WeakSet<DeepRequired<U>> : T extends Promise<infer U> ? Promise<DeepRequired<U>> : T extends {} ? {
    [K in keyof T]-?: DeepRequired<T[K]>;
} : NonNullable<T>;
type RequiredExcept<T, K extends keyof T> = Partial<Pick<T, K>> & Required<Omit<T, K>>;
type PartialRequired<T, K extends keyof T> = Partial<Omit<T, K>> & Required<Pick<T, K>>;
type DeepPartial<T> = {
    [P in keyof T]?: T[P] extends Array<infer U> ? Array<DeepPartial<U>> : T[P] extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : DeepPartial<T[P]>;
};
type ArgumentTypes<F extends (...args: any[]) => unknown> = F extends (...args: infer A) => any ? A : never;
/**
 * A readonly array of any values.
 */
type AnyReadonlyArray = readonly any[];
/**
 * A generic constructor with parameters
 */
type Ctor<A extends AnyReadonlyArray = readonly any[], R = any> = new (...args: A) => R;
/**
 * A generic abstract constructor with parameters
 */
type AbstractCtor<A extends AnyReadonlyArray = readonly any[], R = any> = abstract new (...args: A) => R;
/**
 * A generic constructor without parameters
 */
type Constructor<T> = new (...args: any[]) => T;
/**
 * A generic abstract constructor without parameters
 */
type AbstractConstructor<T> = abstract new (...args: any[]) => T;
/**
 * Gets the first argument of any given function
 */
type FirstArgument<T> = T extends (arg1: infer U, ...args: unknown[]) => unknown ? U : unknown;
/**
 * Gets the second argument of any given function
 */
type SecondArgument<T> = T extends (arg1: unknown, arg2: infer U, ...args: unknown[]) => unknown ? U : unknown;
/**
 * ReturnType for a function that can return either a value or a `Promise` with that value
 */
type Awaitable<T> = PromiseLike<T> | T;
/**
 * Type union for the full 2 billion dollar mistake in the JavaScript ecosystem
 */
type Nullish = null | undefined;
/**
 * Similar to the built in {@link NonNullable}, but properly removes `null` from all keys in the class or interface
 * This does not recurse deeply, for that use {@link DeepRequired}
 */
type NonNullableProperties<T = unknown> = {
    [P in keyof T]: NonNullable<T[P]>;
};
/**
 * An object that is non nullable, to bypass TypeScript not easily working with `Record<PropertyKey, unknown>` in various instances.
 *
 * @deprecated Use the `object` type instead.
 */
type NonNullObject = {} & object;
/**
 * An object that can have any structure, this is an alternative to {@link NonNullObject} for situations where
 * that leads to unexpected type resolutions.
 *
 * Note that this is still a strictly typed type, it is not simply aliasing `any`
 *
 * @deprecated Use the `object` type instead.
 */
type AnyObject<T> = {
    [K in keyof T]: T[K];
};
/**
 * An utility type that fuses intersections of objects.
 *
 * @example
 *
 * ```typescript
 * type Objects = {
 *   foo: string;
 *   bar: number;
 * } & {
 *   hello: boolean;
 *   world: bigint;
 * };
 *
 * type PrettyObjects = PrettifyObject<Objects>;
 * // {
 * //   foo: string;
 * //   bar: number;
 * //   hello: boolean;
 * //   world: bigint
 * // }
 * ```
 */
type PrettifyObject<T extends object> = {
    [K in keyof T]: T[K];
};
/**
 * Gets all the keys (as a string union) from a type `T` that match value `V`
 * @example
 * ```typescript
 * interface Sample {
 * 	id: string;
 * 	name: string | null;
 * 	middleName?: string;
 * 	lastName: string;
 * 	hobbies: readonly string[];
 * }
 *
 * type BB = PickByValue<Sample, string>;
 * // Expected:
 * // "id" | "lastName"
 * ```
 */
type PickByValue<T, V> = {
    [P in keyof T]: T[P] extends V ? P : never;
}[keyof T] & keyof T;
/**
 * Transforms a `readonly` type to be mutable
 * @example
 * ```typescript
 * interface Sample {
 * 	id: string;
 * 	hobbies: readonly string[];
 * }
 *
 * type BB = Mutable<Sample>;
 * // Expected:
 * // {
 * //    id: string;
 * //    hobbies: string[];
 * // }
 * ```
 */
type Mutable<T> = {
    -readonly [P in keyof T]: T[P] extends Array<unknown> | object ? Mutable<T[P]> : T[P];
};
/**
 * Transforms every key in an object to be strictly required, essentially removing `undefined` and `null` from the type.
 * @example
 * ```typescript
 * interface Sample {
 * 	id: string;
 * 	name: string | null;
 * 	middleName?: string;
 * }
 *
 * type BB = StrictRequired<Sample>;
 * // Expected:
 * // {
 * //    id: string;
 * //    name: string;
 * //    middleName: string;
 * // }
 * ```
 */
type StrictRequired<T> = {
    [P in keyof T]-?: NonNullable<T[P]>;
};
/**
 * Gets a union type of all the keys that are in an array.
 * @example
 * ```typescript
 * const sample = [1, 2, '3', true];
 *
 * type arrayUnion = ArrayElementType<typeof sample>;
 * // Expected: string | number | boolean
 * ```
 */
type ArrayElementType<T> = T extends (infer K)[] ? K : T extends readonly (infer RK)[] ? RK : T;
/**
 * A type utility that allows branching of types depending on the `Value` parameter.
 * @example
 * ```typescript
 * declare function get<const GetValues extends boolean = false>(
 *   getValues?: GetValues
 * ): If<GetValues, string, string[]>;
 *
 * const a = get(true);
 * //    ^? string
 *
 * const b = get(false);
 * //    ^? string[]
 *
 * declare const someBoolean: boolean;
 * const c = get(someBoolean);
 * //    ^? string | string[]
 * ```
 */
type If<Value extends boolean, TrueResult, FalseResult> = Value extends true ? TrueResult : Value extends false ? FalseResult : TrueResult | FalseResult;
/**
 * A type utility that allows branching of an union type on the `Value` parameter.
 * @example
 * ```typescript
 * declare function get<const Required extends boolean = false>(
 *   required?: Required
 * ): If<Required, string>;
 *
 * const a = get(true);
 * //    ^? string
 *
 * const b = get(false);
 * //    ^? string | null
 *
 * declare const someBoolean: boolean;
 * const c = get(someBoolean);
 * //    ^? string | null
 * ```
 */
type RequiredIf<Value extends boolean, ValueType, FallbackType = null> = If<Value, ValueType, ValueType | FallbackType>;

export type { AbstractConstructor, AbstractCtor, AnyObject, AnyReadonlyArray, ArgumentTypes, ArrayElementType, Awaitable, Builtin, Constructor, Ctor, DeepPartial, DeepReadonly, DeepRequired, FirstArgument, If, Mutable, NonNullObject, NonNullableProperties, Nullish, PartialRequired, PickByValue, PrettifyObject, Primitive, RequiredExcept, RequiredIf, SecondArgument, StrictRequired };
