Skip to content

Commit

Permalink
Added new types and refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
djalmajr committed Jul 8, 2022
1 parent ca64977 commit 8f13bfe
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 92 deletions.
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@
}
},
"scripts": {
"build": "bin/build.mjs minify=true && npm run build:types",
"build:dev": "bin/build.mjs watch=true",
"build:types": "tsc --emitDeclarationOnly && cp src/types.d.ts lib && echo \"export * from './types';\" >> lib/index.d.ts",
"prettier": "prettier --write src/**/*.ts",
"build": "bin/build.mjs minify=true && npm run build:types",
"postversion": "git push && git push --tags && npm publish",
"test": "exit 0",
"prebuild": "npm run test",
"prettier": "prettier --write src/**/*.ts",
"test:prettier": "prettier --check src/**/*.ts",
"test:ts": "tsc --noEmit",
"test": "npm run test:ts && npm run test:prettier",
"version": "npm run prettier && npm run build"
},
"devDependencies": {
Expand Down
3 changes: 1 addition & 2 deletions src/clone.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { isObject } from './isObject';
import { Any } from './types';

/**
* http://documentcloud.github.io/underscore-contrib/#snapshot
Expand All @@ -11,7 +10,7 @@ export function clone<T extends object>(data: T): T {
return data;
}

const res = new (data as Any).constructor();
const res = new (data as any).constructor(); // eslint-disable-line

for (const key in data) {
if (data.hasOwnProperty(key)) {
Expand Down
18 changes: 4 additions & 14 deletions src/curry.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
import { Any, Fn } from './types';
/* eslint-disable @typescript-eslint/no-explicit-any */

export type Curried<A extends Any[], R> = <P extends Partial<A>>(
...args: P
) => P extends A
? R
: A extends [...SameLength<P>, ...infer S]
? S extends Any[]
? Curried<S, R>
: never
: never;

export type SameLength<T extends Any[]> = Extract<{ [K in keyof T]: Any }, Any[]>;
import { Curried, Fn } from './types';

export const __ = Symbol('help-es');

Expand All @@ -34,11 +24,11 @@ const cat = (prev: unknown[], next: unknown[]) => {
* console.log(toSquare(9)) // logs 81
*/
export function curry<A extends unknown[], R>(fn: Fn<A, R>): Curried<A, R> {
return function curried(...args: Any[]): Any {
return function curried(...args: any[]): any {
if (args.some((a) => a === __) || args.length < fn.length) {
return (...next: unknown[]) => curried(...cat(args, next));
}

return fn(...(args as Any));
return fn(...(args as any));
};
}
3 changes: 2 additions & 1 deletion src/flow.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Fn } from './types';

export function flow<R = unknown>(...fns: Fn<unknown[], unknown>[]) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function flow<R = unknown>(...fns: Fn<[...any], unknown>[]) {
return (x: unknown) => fns.reduce((y, f) => f(y), x) as R;
}
2 changes: 1 addition & 1 deletion src/isObj.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isArr } from './isArr';
import { isObject } from './isObject';

export function isObj(a: unknown): a is Record<string, unknown> {
export function isObj<T extends object>(a: unknown): a is T {
return isObject(a) && !isArr(a);
}
33 changes: 4 additions & 29 deletions src/merge.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,6 @@
import { curry } from './curry';
import { isObject } from './isObject';
import { Any, Obj } from './types';

/***
* https://stackoverflow.com/a/49683575/2528550
*/

export type OptionalPropertyNames<T> = {
[K in keyof T]-?: Obj extends { [P in K]: T[K] } ? K : never;
}[keyof T];

export type SpreadProperties<L, R, K extends keyof L & keyof R> = {
[P in K]: L[P] | Exclude<R[P], undefined>;
};

export type Id<T> = T extends infer U ? { [K in keyof U]: U[K] } : never;

export type SpreadTwo<L, R> = Id<
Pick<L, Exclude<keyof L, keyof R>> &
Pick<R, Exclude<keyof R, OptionalPropertyNames<R>>> &
Pick<R, Exclude<OptionalPropertyNames<R>, keyof L>> &
SpreadProperties<L, R, OptionalPropertyNames<R> & keyof L>
>;

export type Spread<A extends readonly [...Any]> = A extends [infer L, ...infer R]
? SpreadTwo<L, Spread<R>>
: unknown;
import { Obj, Spread } from './types';

const getCtor = (v: Obj) => v.constructor;

Expand All @@ -34,11 +9,11 @@ export interface MergeFn {
<A extends object, B extends object>(a: A, b: B): Spread<[A, B]>;
}

export const merge = curry((target: Obj<Any>, source: never) => {
export const merge = curry((target: Obj, source: never) => {
for (const [key, val] of Object.entries(source)) {
if (isObject(val)) {
if (target[key] === void 0 || getCtor(target[key]) !== getCtor(val as Obj)) {
target[key] = new (val as Any).constructor();
if (target[key] === undefined || getCtor(target[key]) !== getCtor(val as Obj)) {
target[key] = new (val as any).constructor(); // eslint-disable-line
}

merge(target[key], val);
Expand Down
2 changes: 1 addition & 1 deletion src/pick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface PickFn {
export const pick = curry((path: string | string[], obj: Obj) => {
const keys = ([] as string[]).concat(path);

return keys.reduce(function (res, key) {
return keys.reduce((res, key) => {
if (obj.hasOwnProperty(key)) {
res[key] = obj[key];
}
Expand Down
150 changes: 109 additions & 41 deletions src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,117 +1,185 @@
export declare type Any = any; // eslint-disable-line
/* eslint-disable @typescript-eslint/no-explicit-any */

export declare type PropKey = number | string;
export declare type PropKey = number | string | symbol;

export declare type Fn<A extends unknown[], R> = (...args: A) => R;

export declare type Obj<T = Any> = Record<PropKey, T>;
export declare type Obj<T = any> = Record<PropKey, T>;

export declare type ValueOf<T> = T[keyof T];

export declare type Constructor<T> = new (...args: Any[]) => T;
export declare type Constructor<T> = new (...args: any[]) => T;

export declare type SameLength<T extends Any[]> = Extract<{ [K in keyof T]: Any }, Any[]>;
/******************************************************************************/

export declare type Curried<A extends Any[], R> = <P extends Partial<A>>(
export declare type SameLength<T extends any[]> = Extract<{ [K in keyof T]: any }, any[]>;

export declare type Curried<A extends any[], R> = <P extends Partial<A>>(
...args: P
) => P extends A
? R
: A extends [...SameLength<P>, ...infer S]
? S extends Any[]
? S extends any[]
? Curried<S, R>
: never
: never;

export declare type Head<T extends Any[]> = T extends [Any, ...Any[]] ? T[0] : never;
/******************************************************************************/

/***
* https://stackoverflow.com/a/49683575/2528550
*/

export type OptionalPropertyNames<T> = {
[K in keyof T]-?: Obj extends { [P in K]: T[K] } ? K : never;
}[keyof T];

export type SpreadProperties<L, R, K extends keyof L & keyof R> = {
[P in K]: L[P] | Exclude<R[P], undefined>;
};

export type Id<T> = T extends infer U ? { [K in keyof U]: U[K] } : never;

export type SpreadTwo<L, R> = Id<
Pick<L, Exclude<keyof L, keyof R>> &
Pick<R, Exclude<keyof R, OptionalPropertyNames<R>>> &
Pick<R, Exclude<OptionalPropertyNames<R>, keyof L>> &
SpreadProperties<L, R, OptionalPropertyNames<R> & keyof L>
>;

export type Spread<A extends readonly [...any]> = A extends [infer L, ...infer R]
? SpreadTwo<L, Spread<R>>
: unknown;

export declare type Tail<T extends Any[]> = ((...t: T) => Any) extends (
_: Any,
/******************************************************************************/

export declare type Head<T extends any[]> = T extends [any, ...any[]] ? T[0] : never;

export declare type Tail<T extends any[]> = ((...t: T) => any) extends (
_: any,
...tail: infer TT
) => Any
) => any
? TT
: [];

export declare type HasTail<T extends Any[]> = T extends [] | [Any] ? false : true;
export declare type HasTail<T extends any[]> = T extends [] | [any] ? false : true;

export declare type Last<T extends Any[]> = {
export declare type Last<T extends any[]> = {
0: Last<Tail<T>>;
1: Head<T>;
}[HasTail<T> extends true ? 0 : 1];

export declare type Length<T extends Any[]> = T['length'];
export declare type Length<T extends any[]> = T['length'];

export declare type Prepend<E, T extends Any[]> = ((head: E, ...args: T) => Any) extends (
export declare type Prepend<E, T extends any[]> = ((head: E, ...args: T) => any) extends (
...args: infer U
) => Any
) => any
? U
: T;

export declare type Drop<N extends number, T extends Any[], I extends Any[] = []> = {
0: Drop<N, Tail<T>, Prepend<Any, I>>;
export declare type Drop<N extends number, T extends any[], I extends any[] = []> = {
0: Drop<N, Tail<T>, Prepend<any, I>>;
1: T;
}[Length<I> extends N ? 1 : 0];

export declare type Cast<X, Y> = X extends Y ? X : Y;

export declare type Pos<I extends Any[]> = Length<I>;
export declare type Pos<I extends any[]> = Length<I>;

export declare type Next<I extends Any[]> = Prepend<Any, I>;
export declare type Next<I extends any[]> = Prepend<any, I>;

export declare type Prev<I extends Any[]> = Tail<I>;
export declare type Prev<I extends any[]> = Tail<I>;

export declare type Iterator<
Index extends number = 0,
From extends Any[] = [],
I extends Any[] = [],
From extends any[] = [],
I extends any[] = [],
> = {
0: Iterator<Index, Next<From>, Next<I>>;
1: From;
}[Pos<I> extends Index ? 1 : 0];

export declare type Reverse<T extends Any[], R extends Any[] = [], I extends Any[] = []> = {
export declare type Reverse<T extends any[], R extends any[] = [], I extends any[] = []> = {
0: Reverse<T, Prepend<T[Pos<I>], R>, Next<I>>;
1: R;
}[Pos<I> extends Length<T> ? 1 : 0];

export declare type Concat<T1 extends Any[], T2 extends Any[]> = Reverse<
Reverse<T1> extends infer R ? Cast<R, Any[]> : never,
export declare type Concat<T1 extends any[], T2 extends any[]> = Reverse<
Reverse<T1> extends infer R ? Cast<R, any[]> : never,
T2
>;

export declare type Append<E, T extends Any[]> = Concat<T, [E]>;
export declare type Append<E, T extends any[]> = Concat<T, [E]>;

/******************************************************************************/

// https://github.com/microsoft/TypeScript/issues/32164#issuecomment-764660652
export type Overloads<T> = T extends {
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
(...args: infer A3): infer R3;
(...args: infer A4): infer R4;
}
? [(...args: A1) => R1, (...args: A2) => R2, (...args: A3) => R3, (...args: A4) => R4]
: T extends {
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
(...args: infer A3): infer R3;
}
? [(...args: A1) => R1, (...args: A2) => R2, (...args: A3) => R3]
: T extends {
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
}
? [(...args: A1) => R1, (...args: A2) => R2]
: T extends {
(...args: infer A1): infer R1;
}
? [(...args: A1) => R1]
: any;

export type OverloadedParameters<T> = Overloads<T> extends infer O
? { [K in keyof O]: Parameters<Extract<O[K], (...args: any) => any>> }
: never;

export type OverloadedReturnType<T> = Overloads<T> extends infer O
? { [K in keyof O]: ReturnType<Extract<O[K], (...args: any) => any>> }
: never;

/******************************************************************************/

/**
* https://www.freecodecamp.org/news/typescript-curry-ramda-types-f747e99744ab/
*/
export declare namespace Curry {
type GapOf<
T1 extends Any[],
T2 extends Any[],
TN extends Any[],
I extends Any[],
T1 extends any[],
T2 extends any[],
TN extends any[],
I extends any[],
> = T1[Pos<I>] extends R.Placeholder ? Append<T2[Pos<I>], TN> : TN;

type GapsOf<T1 extends Any[], T2 extends Any[], TN extends Any[] = [], I extends Any[] = []> = {
0: GapsOf<T1, T2, GapOf<T1, T2, TN, I> extends infer G ? Cast<G, Any[]> : never, Next<I>>;
1: Concat<TN, Drop<Pos<I>, T2> extends infer D ? Cast<D, Any[]> : never>;
type GapsOf<T1 extends any[], T2 extends any[], TN extends any[] = [], I extends any[] = []> = {
0: GapsOf<T1, T2, GapOf<T1, T2, TN, I> extends infer G ? Cast<G, any[]> : never, Next<I>>;
1: Concat<TN, Drop<Pos<I>, T2> extends infer D ? Cast<D, any[]> : never>;
}[Pos<I> extends Length<T1> ? 1 : 0];

type PartialGaps<T extends Any[]> = {
type PartialGaps<T extends any[]> = {
[K in keyof T]?: T[K] | R.Placeholder;
};

type CleanedGaps<T extends Any[]> = {
type CleanedGaps<T extends any[]> = {
[K in keyof T]: NonNullable<T[K]>;
};

type Gaps<T extends Any[]> = CleanedGaps<PartialGaps<T>>;
type Gaps<T extends any[]> = CleanedGaps<PartialGaps<T>>;

type Curry<F extends (...args: Any) => Any> = <T extends Any[]>(
...args: Cast<Cast<T, Gaps<Parameters<F>>>, Any[]>
) => GapsOf<T, Parameters<F>> extends [Any, ...Any[]]
type Curry<F extends (...args: any) => any> = <T extends any[]>(
...args: Cast<Cast<T, Gaps<Parameters<F>>>, any[]>
) => GapsOf<T, Parameters<F>> extends [any, ...any[]]
? Curry<
(
...args: GapsOf<T, Parameters<F>> extends infer G ? Cast<G, Any[]> : never
...args: GapsOf<T, Parameters<F>> extends infer G ? Cast<G, any[]> : never
) => ReturnType<F>
>
: ReturnType<F>;
Expand Down

0 comments on commit 8f13bfe

Please sign in to comment.