types-ramda
Version:
Dedicated types library for ramda
548 lines (490 loc) • 15.6 kB
TypeScript
import { A, M } from 'ts-toolbelt';
// Here lies a loose collection of tools that compute types for the functions in "index.d.ts"
// The goal of this file is to keep "index.d.ts" readable as well as hiding implementations
// WHEN ADDING A NEW TOOL
// - Add documentation for the tool you've created
// - Add <created by @username> on your tool's docs
// TODO
// - Types need proper descriptions, so that we know what they do
/**
* Array of functions to compose/pipe with.
*/
export type AtLeastOneFunctionsFlow<TArgs extends any[], TResult> =
| [(...args: TArgs) => any, ...Array<(args: any) => any>, (...args: any[]) => TResult]
| [(...args: TArgs) => TResult];
export type AtLeastOneFunctionsFlowFromRightToLeft<TArgs extends any[], TResult> =
| [(...args: any) => TResult, ...Array<(args: any) => any>, (...args: TArgs) => any]
| [(...args: TArgs) => TResult];
/**
* R.cond's [predicate, transform] pair.
*/
export type CondPair<T extends any[], R> = [(...val: T) => boolean, (...val: T) => R];
/**
* R.cond's [predicate, transform] pair in a typeguarded version
*/
export type CondPairTypeguard<T, TFiltered extends T, R> = [(value: T) => value is TFiltered, (value: TFiltered) => R];
/**
* A conditional type to use with default values. (defaultTo, propOr, etc)
* <created by @lax4mike>
*/
export type DefaultTo<Fallback, Value> = (Value extends (null | undefined) ? Fallback | Exclude<Value, null | undefined> : Value);
/**
* Represents all objects evolvable with Evolver E
* @param E
*/
export type Evolvable<E extends Evolver> = {
[P in keyof E]?: Evolved<E[P]>;
};
/**
* <needs description>
* @param O
* @param E
*/
export type Evolve<O extends Evolvable<E>, E extends Evolver> = {
[P in keyof O]: P extends keyof E ? EvolveValue<O[P], E[P]> : O[P];
};
/**
* <needs description>
* @param A
*/
type Evolved<A> = A extends (value: infer V) => any ? V : A extends Evolver ? Evolvable<A> : never;
/**
* A set of transformation to run as part of an evolve
* @param T - the type to be evolved
*/
export type Evolver<T extends Evolvable<any> = any> = {
// if T[K] isn't evolvable, don't allow nesting for that property
[key in keyof Partial<T>]: ((value: T[key]) => T[key]) | (T[key] extends Evolvable<any> ? Evolver<T[key]> : never);
};
/**
* <needs description>
* @param O
* @param E
*/
type EvolveNestedValue<O, E extends Evolver> = O extends object
? O extends Evolvable<E>
? Evolve<O, E>
: never
: never;
/**
* <needs description>
* @param V
* @param E
*/
type EvolveValue<V, E> = E extends (value: V) => any
? ReturnType<E>
: E extends Evolver
? EvolveNestedValue<V, E>
: never;
/**
* All falsy JavaScript values representable by the type system.
*
* @note Actually there are six (seven) falsy values in JS - the sixth being `NaN`;
* the seventh being `document.all`. However `NaN` is not a valid literal type,
* and `document.all` is an object so it's probably not a good idea to add it either.
*/
export type Falsy = undefined | null | 0 | '' | false;
/**
* A functor satisfying the FantasyLand spec
* @param A
*/
export type Functor<A> =
| { ['fantasy-land/map']: <B>(fn: (a: A) => B) => Functor<B>; [key: string]: any }
| { map: <B>(fn: (a: A) => B) => Functor<B>; [key: string]: any };
/**
* A Functor - a simple type representing a Functor that used `map` is the method prop name
*/
export type FunctorMap<A> = {
map<B>(fn: (a: A) => B): FunctorMap<B>;
};
/**
* A FantasyLand Functor - a simple type representing a Functor wiih the fantasy-land specific prop name
*/
export type FunctorFantasyLand<A> = {
['fantasy-land/map']<B>(fn: (a: A) => B): FunctorFantasyLand<B>;
};
/**
* R.any dispatches to `.any` of the second argument, if present.
* This type infers the type of the first argument of that method and returns it
*/
export type InferAnyAType<T> = T extends { any: (fn: (a: infer A) => boolean) => boolean } ? A : never;
/**
* A pair containing the key and corresponding value of an object.
* @param K Key type
* @param V Value type
*/
export type KeyValuePair<K, V> = [K, V];
/**
* <needs description>
* @param S Type of the full object
* @param A Type of the lens focus
*/
export type Lens<S, A> = (functorFactory: (a: A) => Functor<A>) => (s: S) => Functor<S>;
/**
* Returns true if T1 array length less than or equal to length of array T2, else returns false
*
* @param T1 First readonly array
* @param T2 Second readonly array
*
* <created by @valerii15298>
*/
type Arr1LessThanOrEqual<
T1 extends ReadonlyArray<any>,
T2 extends ReadonlyArray<any>
> = T1['length'] extends T2['length']
? true
: T2['length'] extends 0
? false
// eslint-disable-next-line @typescript-eslint/no-unused-vars
: T2 extends readonly [infer First, ...infer Rest]
? Arr1LessThanOrEqual<T1, Rest>
: never;
/**
* R.all dispatches to `.all` of the second argument, if present.
* This type infers the type of the first argument of that method and returns it
*/
export type InferAllAType<T> = T extends { all: (fn: (a: infer A) => boolean) => boolean } ? A : never;
/**
* Return true if types T1 and T2 can intersect, e.g. both are primitives or both are objects.
* Taking into account branded types too.
*
* @param T1 First readonly array
* @param T2 Second readonly array
*
* <created by @valerii15298>
*/
type Intersectable<T1, T2> = [T1] extends [T2]
? true
: [T2] extends [T1]
? true
: [T1] extends [object]
? [T2] extends [object]
? true
: false
: [T1] extends [M.Primitive]
? [T2] extends [M.Primitive]
? true
: false
: false;
/**
* Check if type `T` is `any`
*
* @param T Type to check
*
* <created by @valerii15298>
*/
type IsAny<T> = 0 extends 1 & T ? true : false;
/**
* Intersection when produced result can be usable type.
* For example type `{a: any} & number` will not be reduced to `never`
* but `Intersection<{a: any}, number>` will be `never`
* If one of type is any, another type will be returned.
*
* @param T1
* @param T2
*
* <created by @valerii15298>
*/
type Intersection<T1, T2> = Intersectable<T1, T2> extends true
? IsAny<T1> extends true
? T2
: IsAny<T2> extends true
? T1
: T1 & T2
: never;
/**
* Merge second array with first one,
* resulting array will have the same length as array T1,
* every item in new array will be item from first array(T1) by corresponding index
* intersected with item from second array(also with the same index) if such exist
*
* examples:
* `mergeArrWithLeft<[1, number, number, string], [number, 2, 7]>` => `[1, 2, 7, string]`
* `mergeArrWithLeft<[1, string], [number, "exact text", number, any]>` => `[1, "exact text"]`
*
* @param T1
* @param T2
*
* <created by @valerii15298>
*/
export type mergeArrWithLeft<T1 extends ReadonlyArray<any>, T2 extends ReadonlyArray<any>> = readonly [
...{
readonly [Index in keyof T1]: Index extends keyof T2 ? Intersection<T1[Index], T2[Index]> : T1[Index];
}
];
/**
* The same as mergeArrWithLeft but will merge smaller array to larger one,
* so that data will not be lost and maximum length array will be returned
*
* example: MergeArrays<[1, number], [number, 2, string]>
* will result to => [1, 2, string]
*
* @param T1
* @param T2
*
* <created by @valerii15298>
*/
type MergeArrays<T1 extends ReadonlyArray<any>, T2 extends ReadonlyArray<any>> = Arr1LessThanOrEqual<
T1,
T2
> extends true
? mergeArrWithLeft<T2, T1>
: mergeArrWithLeft<T1, T2>;
/**
* Given array of functions will return new array which will be constructed
* merging all functions parameters array using mergeArrays generic.
*
* If provided array is not array of functions, return type will be empty array([])
*
* @param T Array of functions
*
* <created by @valerii15298>
*/
export type LargestArgumentsList<T extends ReadonlyArray<any>> = T extends readonly [
(...args: infer Args) => any,
...infer Rest
]
? MergeArrays<LargestArgumentsList<Rest>, Args>
: readonly [];
/**
* Checks if type is `never`
*
* Returns `true` if type is `never`, else returns `false`
*
* @param T Type to check
*
* <created by @valerii15298>
*/
type IsNever<T> = [T] extends [never] ? true : false;
/**
* Checks if array of types is contains `never` type
*
* Returns `true` if array contains `never` type, else returns `false`
*
* @param T Array of types to check
*
* <created by @valerii15298>
*/
type HasNever<T extends readonly any[]> = T extends readonly [infer First, ...infer Rest]
? IsNever<First> extends true
? true
: HasNever<Rest>
: false;
/**
* Checks if corresponding types of arguments in functions overlap(have at least one type in common, except never)
*
* Returns `unknown` if arguments types overlap, else returns `ErrorMsg`
*
* @param T Type to check
*
* <created by @valerii15298>
*/
export type IfFunctionsArgumentsDoNotOverlap<T extends ReadonlyArray<Fn>, ErrorMsg extends string> = HasNever<
LargestArgumentsList<T>
> extends true
? ErrorMsg
: unknown;
/**
* Predicate for an object containing the key.
*/
export type ObjPred<T = unknown> = (value: any, key: unknown extends T ? string : keyof T) => boolean;
/**
* Values that can be compared using the relational operators `<`/`<=`/`>`/`>=`
*/
export type Ord = number | string | boolean | Date | bigint;
/**
* `a` is less than `b`
*/
export type LT = -1;
/**
* `a` is equal to `b`
*/
export type EQ = 0;
/**
* `a` is greater than `b`
*/
export type GT = 1;
/**
* Represents two values' order
*/
export type Ordering = LT | EQ | GT;
/**
* An object with at least one of its properties beeing of type `Key`.
*
* @example
* ```
* // $ExpectType { foo: unknown } | { bar: unknown }
* type Foo = ObjectHavingSome<"foo" | "bar">
* ```
*/
// Implementation taken from
// https://github.com/piotrwitek/utility-types/blob/df2502ef504c4ba8bd9de81a45baef112b7921d0/src/mapped-types.ts#L351-L362
export type ObjectHavingSome<Key extends PropertyKey> = {
[K in Key]: { [P in K]: unknown };
}[Key];
/**
* Composition of `Partial` and `Record` types
*/
export type PartialRecord<K extends keyof any, T> = Partial<Record<K, T>>;
/**
* <needs description>
*/
export type Path = Array<number | string>;
/**
* A placeholder used to skip parameters, instead adding a parameter to the returned function.
*/
export type Placeholder = A.x & { '@@functional/placeholder': true };
/**
* A runtime-branded value used to stop `reduce` and `transduce` early.
* @param A The type of the contained value
*/
export interface Reduced<A> {
'@@transducer/value': A;
'@@transducer/reduced': true;
}
/**
* A type representing any function. Useful as a generic constraint.
*/
export type Fn = (...args: any[]) => unknown;
/**
* Converts an array of functions to an array of their return types.
* @param A The array of functions
*/
export type ReturnTypesOfFns<A extends ReadonlyArray<Fn>> = A extends readonly [(...args: any[]) => infer H, ...infer R]
? R extends readonly Fn[]
? readonly [H, ...ReturnTypesOfFns<R>]
: readonly []
: readonly [];
/**
* Converts an array of functions taking a single parameter to an array of their parameter types.
* @param A The array of functions
*/
export type InputTypesOfFns<A extends ReadonlyArray<Fn>> = A extends [infer H, ...infer R]
? H extends Fn
? R extends Fn[]
? [Parameters<H>[0], ...InputTypesOfFns<R>]
: []
: []
: [];
/**
* If `T` is a union, `T[keyof T]` (cf. `map` and `values` in `index.d.ts`) contains the types of object values that are common across the union (i.e., an intersection).
* Because we want to include the types of all values, including those that occur in some, but not all members of the union, we first define `ValueOfUnion`.
* @see https://stackoverflow.com/a/60085683
* @param T The (possible) union
*/
export type ValueOfUnion<T> = T extends infer U ? U[keyof U] : never;
/**
* Take first `N` types of an Tuple
* @param N Length of prefix to take
* @param Tuple Input tuple type
*/
export type Take<
N extends number,
Tuple extends any[],
ReturnTuple extends any[] = []
> = ReturnTuple['length'] extends N
? ReturnTuple
: Tuple extends [infer X, ...infer Xs]
? Take<N, Xs, [...ReturnTuple, X]>
: never;
/**
* A homogeneous tuple of length `N`.
* @param T Type of every element of the tuple
* @param N Length of the tuple
*/
export type Tuple<T, N extends number> = N extends N ? (number extends N ? T[] : _TupleOf<T, N, []>) : never;
type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]>;
/**
* Map tuple of ordinary type to tuple of array type
* [string, number] -> [string[], number[]]
*/
export type ToTupleOfArray<Tuple extends any[]> = Tuple extends []
? []
: Tuple extends [infer X, ...infer Xs]
? [X[], ...ToTupleOfArray<Xs>]
: never;
/**
* Map tuple of ordinary type to tuple of function type
* @param R Parameter type of every function
* @param Tuple Return type of every function
*/
export type ToTupleOfFunction<R, Tuple extends any[]> = Tuple extends []
? []
: Tuple extends [infer X, ...infer Xs]
? [(arg: R) => X, ...ToTupleOfFunction<R, Xs>]
: never;
/**
* Getter of property from any value. Supports objects, arrays, tuples and maybe values
*
* @param T Value type
* @param P Maybe key type
*
* @example
* ```typescript
* type K = Prop<{ x: number } | undefined, 'x'>
* type L = Prop<[1, ...string[]] | undefined, 0>
* type M = Prop<[1, ...string[]] | undefined, 1>
* ```
*
* <created by @anion155>
*/
export type Prop<T, P extends keyof never> = P extends keyof Exclude<T, undefined>
? T extends undefined ? undefined : T[Extract<P, keyof T>]
: undefined;
/**
* When you have `gt = <T extends Ord>(a: T, b: T) => boolean`, `a` and `b` are different strings, and `T` defaults to `string
* However, `gt = <T extends Ord>(a: T) => (b: T) => boolean`, because `a` is evaluated without `b`, `T` is the literal of `a`
* `WidenLiteral` exists to go from a literal type to its base type, eg
* * `"foobar"` -> `string`
* * `1` -> `number`
* * `true` -> `boolean
* @see https://stackoverflow.com/a/56333836/10107466
*
* <created by @harris-miller>
*/
export type WidenLiterals<T> =
T extends boolean
? boolean
: T extends string
? string
: T extends number
? number
: T;
/**
* Extract the types from an array
* Works with Tuples, eg `ElementOf<typeof ['p1', 'p2']>` => `'p1' | 'p2'`
*
* <created by @harris-miller>
*/
export type ElementOf<Type extends readonly any[]> = Type[number];
/**
* A clever way to represent a non-empty array
* <created by @harris-miller>
*/
export type NonEmptyArray<T> = [T, ...T[]];
/**
* A clever way to represent a readonly non-empty array
* <created by @harris-miller>
*/
export type ReadonlyNonEmptyArray<T> = readonly [T, ...T[]];
/**
* Prettify type into an object literal
* <created by @harris-miller>
*/
export type Prettify<T> = {[KeyType in keyof T]: T[KeyType]} & {};
type TuplesFromObject<T> = {
[P in keyof T]: [P, T[P]];
}[keyof T];
type GetKeyByValue<T, V> =
TuplesFromObject<T> extends infer TT
? TT extends [infer P, V]
? P
: never
: never;
/**
* Remap keys of one object to the values of mapping object
* <created by @RobinTail>
*/
export type Remap<T, U extends { [P in keyof T]?: string }> = {
[P in NonNullable<U[keyof U]>]: T[GetKeyByValue<U, P>];
};