From facfac3ec545dd17d14b12b0e9466dbf39599417 Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Fri, 18 Jan 2019 19:46:25 -0500 Subject: [PATCH] first iterations of types --- types/constant.d.ts | 30 +++++++++++++++++++ types/freeze.d.ts | 12 ++++++++ types/if.d.ts | 13 +++++++++ types/ifElse.d.ts | 13 +++++++++ types/index.d.ts | 30 +++++++++++++++++++ types/is.d.ts | 9 ++++++ types/map.d.ts | 11 +++++++ types/omit.d.ts | 7 +++++ types/omitBy.d.ts | 7 +++++ types/reject.d.ts | 9 ++++++ types/tests.ts | 61 +++++++++++++++++++++++++++++++++++++++ types/tsconfig.json | 14 +++++++++ types/tslint.json | 11 +++++++ types/types.d.ts | 14 +++++++++ types/update.d.ts | 32 ++++++++++++++++++++ types/updateIn.d.ts | 12 ++++++++ types/util/curry.d.ts | 12 ++++++++ types/util/splitPath.d.ts | 2 ++ types/withDefault.d.ts | 8 +++++ types/wrap.d.ts | 2 ++ 20 files changed, 309 insertions(+) create mode 100644 types/constant.d.ts create mode 100644 types/freeze.d.ts create mode 100644 types/if.d.ts create mode 100644 types/ifElse.d.ts create mode 100644 types/index.d.ts create mode 100644 types/is.d.ts create mode 100644 types/map.d.ts create mode 100644 types/omit.d.ts create mode 100644 types/omitBy.d.ts create mode 100644 types/reject.d.ts create mode 100644 types/tests.ts create mode 100644 types/tsconfig.json create mode 100644 types/tslint.json create mode 100644 types/types.d.ts create mode 100644 types/update.d.ts create mode 100644 types/updateIn.d.ts create mode 100644 types/util/curry.d.ts create mode 100644 types/util/splitPath.d.ts create mode 100644 types/withDefault.d.ts create mode 100644 types/wrap.d.ts diff --git a/types/constant.d.ts b/types/constant.d.ts new file mode 100644 index 0000000..9a80a45 --- /dev/null +++ b/types/constant.d.ts @@ -0,0 +1,30 @@ +/** + * Returns a function that always returns the supplied value. + * + * Useful for replacing an object outright rather than merging it. + * + * @memberOf u + * + * @example + * var alwaysFour = u.constant(4); + * expect(alwaysFour(32)).toEqual(4); + * + * @example + * var user = { + * name: 'Mitch', + * favorites: { + * band: 'Nirvana', + * movie: 'The Matrix' + * } + * }; + * + * var newFavorites = { + * band: 'Coldplay' + * }; + * + * var result = u({ favorites: u.constant(newFavorites) }, user); + * + * expect(result).toEqual({ name: 'Mitch', favorites: { band: 'Coldplay' } }); + */ +export declare function constant(value: A): (...args: any[]) => A; +export default constant; diff --git a/types/freeze.d.ts b/types/freeze.d.ts new file mode 100644 index 0000000..e21475a --- /dev/null +++ b/types/freeze.d.ts @@ -0,0 +1,12 @@ +/** + * Deeply freeze a plain javascript object. + * + * If `process.env.NODE_ENV === 'production'`, this returns the original object + * without freezing. + * + * Or if `process.env.UPDEEP_MODE === 'dangerously_never_freeze'`, this returns the original object + * without freezing. + * + */ +declare function freeze(object: O): O; +export default freeze; diff --git a/types/if.d.ts b/types/if.d.ts new file mode 100644 index 0000000..b1ba4bf --- /dev/null +++ b/types/if.d.ts @@ -0,0 +1,13 @@ +import { Predicate, MergedUpdate, TruePredicate, FalsePredicate } from './types'; +export declare function uIf(predicate: FalsePredicate, trueUpdates: TU, object: O): O; +export declare function uIf(predicate: TruePredicate, trueUpdates: TU, object: O): MergedUpdate; +interface CurriedIf { + (predicate: TruePredicate, trueUpdates: TU, object: O): MergedUpdate; + (predicate: FalsePredicate, trueUpdates: TU, object: O): O; + (predicate: Predicate, trueUpdates: TU, object: O): MergedUpdate | O; + (predicate: TruePredicate, trueUpdates: TU): (object: O) => MergedUpdate; + (predicate: FalsePredicate, trueUpdates: TU): (object: O) => O; + (predicate: Predicate, trueUpdates: TU): (object: O) => MergedUpdate | O; +} +declare const _default: CurriedIf; +export default _default; diff --git a/types/ifElse.d.ts b/types/ifElse.d.ts new file mode 100644 index 0000000..6eea6b1 --- /dev/null +++ b/types/ifElse.d.ts @@ -0,0 +1,13 @@ +import { Predicate, MergedUpdate, FalsePredicate, TruePredicate } from './types'; +export declare function updateIfElse(predicate: TruePredicate, trueUpdates: TU, falseUpdates: FU, object: S): MergedUpdate; +export declare function updateIfElse(predicate: FalsePredicate, trueUpdates: TU, falseUpdates: FU, object: S): MergedUpdate; +interface CurriedIfElse { + (predicate: TruePredicate, trueUpdates: TU, falseUpdates: FU, object: S): MergedUpdate; + (predicate: FalsePredicate, trueUpdates: TU, falseUpdates: FU, object: S): MergedUpdate; + (predicate: Predicate, trueUpdates: TU, falseUpdates: FU, object: S): MergedUpdate | MergedUpdate; + (predicate: TruePredicate, trueUpdates: TU, falseUpdates: FU): (object: S) => MergedUpdate; + (predicate: FalsePredicate, trueUpdates: TU, falseUpdates: FU): (object: S) => MergedUpdate; + (predicate: Predicate, trueUpdates: TU, falseUpdates: FU): (object: S) => MergedUpdate | MergedUpdate; +} +declare const _default: CurriedIfElse; +export default _default; diff --git a/types/index.d.ts b/types/index.d.ts new file mode 100644 index 0000000..15a1c34 --- /dev/null +++ b/types/index.d.ts @@ -0,0 +1,30 @@ +import { constant } from './constant'; +import freeze from './freeze'; +import is from './is'; +import _if from './if'; +import ifElse from './ifElse'; +import map from './map'; +import omit from './omit'; +import omitBy from './omitBy'; +import reject from './reject'; +import update, { omitted } from './update'; +import updateIn from './updateIn'; +import withDefault from './withDefault'; +import { _ as placeholder } from './util/curry'; +declare const u: { + omit: typeof omit; + omitBy: typeof omitBy; + constant: typeof constant; + freeze: typeof freeze; + is: typeof is; + update: typeof update; + updateIn: typeof updateIn; + reject: typeof reject; + map: typeof map; + withDefault: typeof withDefault; + ifElse: typeof ifElse; + if: typeof _if; + omitted: typeof omitted; + _: typeof placeholder; +} & typeof update; +export default u; diff --git a/types/is.d.ts b/types/is.d.ts new file mode 100644 index 0000000..a3632c1 --- /dev/null +++ b/types/is.d.ts @@ -0,0 +1,9 @@ +import { Path } from './types'; +export declare function is(path: Path, predicate: any, object: any): boolean; +interface CurriedIs { + (path: Path, predicate: any, object: any): boolean; + (path: Path, predicate: any): (object: any) => boolean; + (path: Path): (predicate: any) => (object: any) => boolean; +} +declare const _default: CurriedIs; +export default _default; diff --git a/types/map.d.ts b/types/map.d.ts new file mode 100644 index 0000000..e8f1549 --- /dev/null +++ b/types/map.d.ts @@ -0,0 +1,11 @@ +import { MergedUpdate } from './types'; +declare type Mapped = { + [K in keyof O]: MergedUpdate; +}; +export declare function map(iteratee: I, object: O): Mapped; +interface CurriedMap { + (iteratee: I, object: O): Mapped; + (iteratee: I): (object: O) => Mapped; +} +declare const _default: CurriedMap; +export default _default; diff --git a/types/omit.d.ts b/types/omit.d.ts new file mode 100644 index 0000000..78bb67b --- /dev/null +++ b/types/omit.d.ts @@ -0,0 +1,7 @@ +export declare function omit(predicate: string[] | string, collection: object): object; +interface CurriedOmit { + (predicate: string[] | string, collection: object): object; + (predicate: string[] | string): (collection: object) => object; +} +declare const _default: CurriedOmit; +export default _default; diff --git a/types/omitBy.d.ts b/types/omitBy.d.ts new file mode 100644 index 0000000..51e6cb8 --- /dev/null +++ b/types/omitBy.d.ts @@ -0,0 +1,7 @@ +export declare function omitBy boolean>(predicate: P, collection: C): object; +interface CurriedOmitBy { + boolean>(predicate: P, collection: C): object; + boolean>(predicate: P): (collection: C) => object; +} +declare const _default: CurriedOmitBy; +export default _default; diff --git a/types/reject.d.ts b/types/reject.d.ts new file mode 100644 index 0000000..2e7938c --- /dev/null +++ b/types/reject.d.ts @@ -0,0 +1,9 @@ +export declare function reject(predicate: any, collection: C): C extends any[] ? C : object; +interface CurriedReject { + (predicate: any, collection: C): C; + (predicate: any, collection: C): Array; + (predicate: any): (collection: C) => C; + (predicate: any): (collection: C) => Array; +} +declare const _default: CurriedReject; +export default _default; diff --git a/types/tests.ts b/types/tests.ts new file mode 100644 index 0000000..2385a55 --- /dev/null +++ b/types/tests.ts @@ -0,0 +1,61 @@ +// TypeScript Version: 3.2.2 +import u from "updeep"; + +u.omitted('whatever'); // $ExpectType { __omitted: boolean; } + +const obj = { this: 3 }; + +u(true, obj); // $ExpectType true +u(null, obj); // $ExpectType null +u(undefined, obj); // $ExpectType undefined +u("a specific string", obj); // $ExpectType "a specific string" + +u(true)(obj); // $ExpectType true +u(null)(obj); // $ExpectType null +u(undefined)(obj); // $ExpectType undefined +u("a specific string")(obj); // $ExpectType "a specific string" + +const aString = "a" + "b"; + +u(aString, obj); // $ExpectType string + +u((i: number) => "foo" + i, 1); // $ExpecType string +u((i: number) => "foo" + i, "bar"); + +// update is object +u({ this: 2 }, true); // $ExpectType UpdateReturnMap<{ this: number; }> +u({ this: 2 })(true); // $ExpectType UpdateReturnMap<{ this: number; }> + +u({ this: 2 }, { this: 3 }); // $ExpectType object +u({ this: 2 })({ that: 3 }); // $ExpectType object + +u({ this: 2 })(true); // UpdateReturnMap<{ this: number; }> +u({ this: 2 })({ that: 3 }); // $ExpectType object + + +u.ifElse(false as boolean, { a: 1 }, { a: 2 }, { a: 3 }); // $ExpectType object +u.ifElse(false as boolean, "foo", 3, { a: 3 }); // $ExpectType string | number +u.ifElse(false, "foo", 3, { a: 3 }); // $ExpectType number +u.ifElse(true, "foo", 3, { a: 3 }); // $ExpectType string + +// *** map *** +const inc = (i:number) => i+1; + +u.map(inc, [1,2,3]); // $ExpectType number[] +u.map(inc, ["potato"]); // $ExpectType number[] +u.map({a:1},{a:2}); // $ExpectType Mapped<{ a: number; }, { a: number; }> + +u.omit('bar', { }); // $ExpectType object +u.omit(['bar'], { }); // $ExpectType object + +u.omitBy([ 'banana' ], { } ); // $ExpectError + +// *** constant *** + +// $ExpectType { banana: number; } +u.constant({ banana: 1 })('foo'); + +/// *** freeze *** + +// $ExpectType { potato: number; } +u.freeze({ potato: 1 }); diff --git a/types/tsconfig.json b/types/tsconfig.json new file mode 100644 index 0000000..80ecf93 --- /dev/null +++ b/types/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": ["es6"], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noEmit": true, + + "baseUrl": "./", + "paths": { "updeep": ["."] } + } +} diff --git a/types/tslint.json b/types/tslint.json new file mode 100644 index 0000000..c0c24d9 --- /dev/null +++ b/types/tslint.json @@ -0,0 +1,11 @@ +{ + "extends": "dtslint/dtslint.json", + "rules": { + "trim-file": false, + "no-consecutive-blank-lines": false, + "typedef-whitespace": false, + "whitespace": false, + "space-within-parens": false, + "prefer-declare-function": false, + "no-unnecessary-generics": false, + "strict-export-declare-modifiers": false } } diff --git a/types/types.d.ts b/types/types.d.ts new file mode 100644 index 0000000..f0640af --- /dev/null +++ b/types/types.d.ts @@ -0,0 +1,14 @@ +export declare type Updates = any; +export declare type Source = any; +export declare type PathPart = number | string; +export declare type Path = PathPart | PathPart[]; +export declare type TruePredicate = true | ((a: S) => true); +export declare type FalsePredicate = false | ((a: S) => false); +export declare type Predicate = boolean | ((arg: S) => boolean); +export declare type MergedUpdate = O extends object ? (UpdateReturnType extends object ? object : UpdateReturnType) : UpdateReturnType; +export declare type UpdateReturnMap = { + [K in keyof T]: UpdateReturnType; +}; +export declare type UpdateReturnType = U extends (object: any) => any ? ReturnType : U extends object ? UpdateReturnMap : U; +export declare type ReturningFunction = (...args: any[]) => any; +export declare type ArgumentsType any> = F extends (...args: infer A) => any ? A : never; diff --git a/types/update.d.ts b/types/update.d.ts new file mode 100644 index 0000000..7fe709a --- /dev/null +++ b/types/update.d.ts @@ -0,0 +1,32 @@ +import { MergedUpdate, UpdateReturnType } from './types'; +export declare const omitted: (...args: any[]) => { + __omitted: boolean; +}; +/** + * Recursively update an object or array. + * + * Can update with values: + * update({ foo: 3 }, { foo: 1, bar: 2 }); + * // => { foo: 3, bar: 2 } + * + * Or with a function: + * update({ foo: x => (x + 1) }, { foo: 2 }); + * // => { foo: 3 } + * + */ +export declare function update(updates: U extends object ? never : U, object: any): U; +export declare function update(updates: U, object: O extends object ? never : O): UpdateReturnType; +export declare function update(updates: U, object: O, ...args: any[]): MergedUpdate; +interface CurriedUpdate1 { + (object: O extends object ? never : O): UpdateReturnType; + (object: O, ...args: any[]): MergedUpdate; +} +interface CurriedUpdate { + (updates: U extends object ? never : U, object: any): U; + (updates: U, object: O extends object ? never : O): UpdateReturnType; + (updates: U, object: O, ...args: any[]): MergedUpdate; + (updates: U extends object ? never : U): (object: any) => U; + (updates: U): CurriedUpdate1; +} +declare const _default: CurriedUpdate; +export default _default; diff --git a/types/updateIn.d.ts b/types/updateIn.d.ts new file mode 100644 index 0000000..62c3be1 --- /dev/null +++ b/types/updateIn.d.ts @@ -0,0 +1,12 @@ +import { Path } from './types'; +export declare function updateIn(path: Path, value: any, object: any): any; +interface Curry2 { + (value: any, object: any): any; + (value: any): (object: any) => any; +} +interface CurriedUpdateIn { + (path: Path, value: any, object: any): any; + (path: Path): Curry2; +} +declare const _default: CurriedUpdateIn; +export default _default; diff --git a/types/util/curry.d.ts b/types/util/curry.d.ts new file mode 100644 index 0000000..546b610 --- /dev/null +++ b/types/util/curry.d.ts @@ -0,0 +1,12 @@ +export declare const _ = "@@updeep/placeholder"; +interface SprawlingCurry { + (...args: A): R; + (): SprawlingCurry; +} +export declare function curry1(fn: (a: A) => R): SprawlingCurry; +export declare function curry1(fn: (a: A, ...args: any) => R): SprawlingCurry; +export declare function curry2(fn: any): any; +export declare function curry3(fn: any): any; +export declare function curry4(fn: any): any; +export default function curry(fn: (...args: any[]) => any, length?: 1 | 2 | 3 | 4): any; +export {}; diff --git a/types/util/splitPath.d.ts b/types/util/splitPath.d.ts new file mode 100644 index 0000000..94529e7 --- /dev/null +++ b/types/util/splitPath.d.ts @@ -0,0 +1,2 @@ +import { Path } from '../types'; +export default function splitPath(path: Path): Array; diff --git a/types/withDefault.d.ts b/types/withDefault.d.ts new file mode 100644 index 0000000..c38c020 --- /dev/null +++ b/types/withDefault.d.ts @@ -0,0 +1,8 @@ +import { MergedUpdate } from './types'; +export declare function withDefault(defaultValue: D, updates: U, object: O): MergedUpdate; +interface CurriedWithDefault { + (defaultValue: D, updates: U, object: O): MergedUpdate; + (defaultValue: D, updates: U): (obj: O) => MergedUpdate; +} +declare const _default: CurriedWithDefault; +export default _default; diff --git a/types/wrap.d.ts b/types/wrap.d.ts new file mode 100644 index 0000000..955b2cf --- /dev/null +++ b/types/wrap.d.ts @@ -0,0 +1,2 @@ +import { ReturningFunction } from './types'; +export default function wrap(func: F, l?: N): any;