From 246ddd52cff782412a25a597029099e53e1fdf43 Mon Sep 17 00:00:00 2001 From: David Philipson Date: Mon, 19 Jun 2017 12:02:45 -0700 Subject: [PATCH 1/5] Fixes to transducers-js types * Remove unnecessary type parameters * Update transduce() and reduce() to accept CompletingTransformers * Fix incorrect definition of transduce() * Fix incorrect definition of reduce() * Fix incorrect definition of completing() * Fix incorrect definition of wrap() * Fix incorrect definition of cat() * Fix overly strict definition of mapcat() * Make into() definition precise with overloads * Use es6 Iterables. * More precise typings for object iteration in reduce(), transduce(), and into() --- types/transducers-js/index.d.ts | 128 +++++++++++++------ types/transducers-js/transducers-js-tests.ts | 48 +++++++ 2 files changed, 137 insertions(+), 39 deletions(-) diff --git a/types/transducers-js/index.d.ts b/types/transducers-js/index.d.ts index cfed8fbbbe..3d9c6f7719 100644 --- a/types/transducers-js/index.d.ts +++ b/types/transducers-js/index.d.ts @@ -1,19 +1,9 @@ // Type definitions for transducers-js 0.4 // Project: https://github.com/cognitect-labs/transducers-js // Definitions by: Colin Kahn +// David Philipson // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -export interface IteratorResult { - done: boolean; - value?: T; -} - -export interface Iterator { - next(value?: any): IteratorResult; - return?(value?: any): IteratorResult; - throw?(e?: any): IteratorResult; -} - export interface Reduced { ['@@transducer/reduced']: boolean; ['@@transducer/value']: TResult; @@ -21,7 +11,7 @@ export interface Reduced { export type Reducer = (result: TResult, input: TInput) => TResult; -export type Transducer = (xf: Transformer) => Transformer; +export type Transducer = (xf: Transformer) => Transformer; export interface CompletingTransformer { ['@@transducer/init'](): TResult | void; @@ -66,7 +56,7 @@ export class Map implements Transformer(f: (x: TInput) => TOutput): Transducer; +export function map(f: (x: TInput) => TOutput): Transducer; export class Filter implements Transformer { constructor(pred: (x: TInput) => boolean, xf: Transformer); @@ -78,13 +68,13 @@ export class Filter implements Transformer { /** * Filtering transducer constructor */ -export function filter(pred: (x: TInput) => boolean): Transducer; +export function filter(pred: (x: TInput) => boolean): Transducer; /** * Similar to filter except the predicate is used to * eliminate values. */ -export function remove(pred: (x: TInput) => boolean): Transducer; +export function remove(pred: (x: TInput) => boolean): Transducer; export class Keep implements Transformer { constructor(f: (x: TInput) => any, xf: Transformer); @@ -97,7 +87,7 @@ export class Keep implements Transformer { * A keeping transducer. Keep inputs as long as the provided * function does not return null or undefined. */ -export function keep(f: (x: TInput) => any): Transducer; +export function keep(f: (x: TInput) => any): Transducer; export class KeepIndexed implements Transformer { constructor(f: (i: number, x: TInput) => any, xf: Transformer); @@ -110,7 +100,7 @@ export class KeepIndexed implements Transformer(f: (i: number, x: TInput) => any): Transducer; +export function keepIndexed(f: (i: number, x: TInput) => any): Transducer; export class Take implements Transformer { constructor(n: number, xf: Transformer); @@ -123,7 +113,7 @@ export class Take implements Transformer { * A take transducer constructor. Will take n values before * returning a reduced result. */ -export function take(n: number): Transducer; +export function take(n: number): Transducer; export class TakeWhile implements Transformer { constructor(pred: (n: TInput) => boolean, xf: Transformer); @@ -136,7 +126,7 @@ export class TakeWhile implements Transformer * Like the take transducer except takes as long as the pred * return true for inputs. */ -export function takeWhile(pred: (n: TInput) => boolean): Transducer; +export function takeWhile(pred: (n: TInput) => boolean): Transducer; export class TakeNth implements Transformer { constructor(n: number, xf: Transformer); @@ -148,7 +138,7 @@ export class TakeNth implements Transformer { /** * A transducer that takes every Nth input */ -export function takeNth(n: number): Transducer; +export function takeNth(n: number): Transducer; export class Drop implements Transformer { constructor(n: number, xf: Transformer); @@ -160,7 +150,7 @@ export class Drop implements Transformer { /** * A dropping transducer constructor */ -export function drop(n: number): Transducer; +export function drop(n: number): Transducer; export class DropWhile implements Transformer { constructor(pred: (input: TInput) => boolean, xf: Transformer); @@ -173,7 +163,7 @@ export class DropWhile implements Transformer * A dropping transducer that drop inputs as long as * pred is true. */ -export function dropWhile(pred: (input: TInput) => boolean): Transducer; +export function dropWhile(pred: (input: TInput) => boolean): Transducer; export class PartitionBy implements Transformer { constructor(f: (input: TInput) => any, xf: Transformer); @@ -187,7 +177,7 @@ export class PartitionBy implements Transformer(f: (input: TInput) => any): Transducer; +export function partitionBy(f: (input: TInput) => any): Transducer; export class PartitionAll implements Transformer { constructor(n: number, xf: Transformer); @@ -200,7 +190,7 @@ export class PartitionAll implements Transformer(n: number): Transducer; +export function partitionAll(n: number): Transducer; export class Completing implements CompletingTransformer { constructor(cf: (result: TResult) => TCompleteResult, xf: Transformer); @@ -213,7 +203,9 @@ export class Completing implements CompletingT * A completing transducer constructor. Useful to provide cleanup * logic at the end of a reduction/transduction. */ -export function completing(cf: (result: TResult) => TCompleteResult): CompletingTransformer; +export function completing( + xf: Transformer | Reducer, + cf: (result: TResult) => TCompleteResult): CompletingTransformer; export class Wrap implements Transformer { constructor(stepFn: Reducer, xf: Transformer); @@ -227,44 +219,102 @@ export class Wrap implements Transformer { * accumluation and the second argument is the next input and convert * it into a transducer transformer object. */ -export function wrap(stepFn: Reducer): Transducer; +export function wrap(stepFn: Reducer): Transformer; /** * Given a transformer return a concatenating transformer */ -export function cat(xf: Transformer): Transformer ; +export function cat(xf: Transformer): Transformer>; /** * A mapping concatenating transformer */ -export function mapcat(f: (arr: TInput[]) => TOutput[]): Transducer; +export function mapcat(f: (arr: TInput) => Iterable): Transducer; /** * Given a transducer, a builder function, an initial value * and a iterable collection - returns the reduction. */ export function transduce( - xf: Transducer, - f: Transformer | Reducer, + xf: Transducer, + f: Reducer, init: TResult, - coll: TInput[] | Iterator | string | Object): TResult; + coll: Iterable): TResult; +export function transduce( + xf: Transducer, + f: CompletingTransformer, + init: TResult, + coll: Iterable): TCompleteResult; +export function transduce( + xf: Transducer, + f: CompletingTransformer, + coll: Iterable): TCompleteResult; +// Overloads for object iteration. +export function transduce( + xf: Transducer<[string, TInput], TOutput>, + f: Reducer, + init: TResult, + coll: { [key: string]: TInput }): TResult; +export function transduce( + xf: Transducer<[string, TInput], TOutput>, + f: CompletingTransformer, + init: TResult, + coll: { [key: string]: TInput }): TCompleteResult; +export function transduce( + xf: Transducer<[string, TInput], TOutput>, + f: CompletingTransformer, + coll: { [key: string]: TInput }): TCompleteResult; /** * Given a transducer, an intial value and a * collection - returns the reduction. */ -export function reduce( - xf: Transducer, +export function reduce( + xf: Transformer | Reducer, init: TResult, - coll: TInput[] | Iterator | string | Object): TResult; + coll: Iterable): TResult; +export function reduce( + xf: CompletingTransformer, + init: TResult, + coll: Iterable): TCompleteResult; +// Overloads for object iteration. +export function reduce( + xf: Transformer | Reducer, + init: TResult, + coll: { [key: string]: TInput }): TResult; +export function reduce( + xf: CompletingTransformer, + init: TResult, + coll: { [key: string]: TInput }): TCompleteResult; /** * Reduce a value into the given empty value using a transducer. */ -export function into( - empty: TResult, - xf: Transducer, - coll: TInput[] | Iterator | string | Object): TResult; +export function into( + empty: TOutput[], + xf: Transducer, + coll: Iterable): TOutput[]; +export function into( + empty: string, + xf: Transducer, + coll: Iterable): string; +export function into( + empty: { [key: string]: TOutput }, + xf: Transducer, + coll: Iterable): { [key: string]: TOutput }; +// Overloads for object iteration. +export function into( + empty: TOutput[], + xf: Transducer<[string, TInput], TOutput>, + coll: { [key: string]: TInput }): TOutput[]; +export function into( + empty: string, + xf: Transducer<[string, TInput], string>, + coll: { [key: string]: TInput }): string; +export function into( + empty: { [key: string]: TOutput }, + xf: Transducer<[string, TInput], [string, TOutput]>, + coll: { [key: string]: TInput }): { [key: string]: TOutput }; /** * Convert a transducer transformer object into a function so @@ -272,7 +322,7 @@ export function into( * Underscore, lodash */ export function toFn( - xf: Transducer, + xf: Transducer, builder: Reducer | Transformer ): Reducer; diff --git a/types/transducers-js/transducers-js-tests.ts b/types/transducers-js/transducers-js-tests.ts index 634309a2b5..f39bf87384 100644 --- a/types/transducers-js/transducers-js-tests.ts +++ b/types/transducers-js/transducers-js-tests.ts @@ -124,3 +124,51 @@ function mapcatExample() { const xf = t.mapcat(reverse); t.into([], xf, [[3, 2, 1], [6, 5, 4]]); // [1, 2, 3, 4, 5, 6] } + +// Original tests + +function transduceExample() { + const { completing, transduce, wrap } = t; + const stringAppendFn = (acc: string, x: number) => acc + x; + const stringAppendTransformer = wrap(stringAppendFn); + const stringAppendThenLengthTransformer = completing( + stringAppendFn, + s => s.length, + ); + const lengthsString1: string = transduce( + t.map((s: string) => s.length), + stringAppendFn, + "", + ["a", "b"], + ); + const lengthsString2: string = transduce( + t.map((s: string) => s.length), + stringAppendTransformer, + "", + ["a", "b"], + ); + const lengthsStringLength: number = transduce( + t.map((s: string) => s.length), + stringAppendThenLengthTransformer, + "", + ["a", "b"], + ); +} + +function advancedIntoExample() { + const array: number[] = into([], t.map((s: string) => s.length), [ + "a", + "b", + ]); + const string: string = into("", t.map((s: string) => s + s), ["a", "b"]); + const object1: { [key: string]: number } = into( + {}, + t.map((s: string) => [s, s.length]), + ["a", "b"], + ); + const object2: { [key: string]: boolean } = into( + {}, + t.map((kv: [string, number]) => [kv[0], true]), + { a: 1, b: 2 } + ); +} From 23455c0bc57a16fd3a7d7ece4d18028929567f5c Mon Sep 17 00:00:00 2001 From: David Philipson Date: Wed, 21 Jun 2017 04:03:15 -0700 Subject: [PATCH 2/5] Fix toFn typing, tweak comp typing --- types/transducers-js/index.d.ts | 9 ++++++--- types/transducers-js/transducers-js-tests.ts | 8 ++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/types/transducers-js/index.d.ts b/types/transducers-js/index.d.ts index 3d9c6f7719..413cfbfef5 100644 --- a/types/transducers-js/index.d.ts +++ b/types/transducers-js/index.d.ts @@ -34,7 +34,10 @@ export function isReduced(x: any): boolean; /** * Function composition. Take N function and return their composition. */ -export function comp(...args: T[]): T; +// Infers correct return type when all arguments have same type. +export function comp any>(...args: T[]): T; +// Falls back to (any => any) when argument types differ. +export function comp(...args: Array<(x: any) => any>): (x: any) => any; /** * Take a predicate function and return its complement. @@ -323,8 +326,8 @@ export function into( */ export function toFn( xf: Transducer, - builder: Reducer | Transformer -): Reducer; + builder: Reducer | Transformer +): Reducer; /** * A transformer which simply returns the first input. diff --git a/types/transducers-js/transducers-js-tests.ts b/types/transducers-js/transducers-js-tests.ts index f39bf87384..7a82b595c8 100644 --- a/types/transducers-js/transducers-js-tests.ts +++ b/types/transducers-js/transducers-js-tests.ts @@ -172,3 +172,11 @@ function advancedIntoExample() { { a: 1, b: 2 } ); } + +function compExample() { + const fn1: t.Transducer = comp(map(inc), filter(isEven)); + const fn2: t.Transducer = comp( + filter(isEven), + map((x: number) => "" + x), + ); +} From 1065599f86fa230995c7aa5bb6ac9ae08513dc9b Mon Sep 17 00:00:00 2001 From: David Philipson Date: Wed, 21 Jun 2017 15:10:21 -0700 Subject: [PATCH 3/5] Fix definition of Wrap --- types/transducers-js/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/transducers-js/index.d.ts b/types/transducers-js/index.d.ts index 413cfbfef5..66073d1cbc 100644 --- a/types/transducers-js/index.d.ts +++ b/types/transducers-js/index.d.ts @@ -211,7 +211,7 @@ export function completing( cf: (result: TResult) => TCompleteResult): CompletingTransformer; export class Wrap implements Transformer { - constructor(stepFn: Reducer, xf: Transformer); + constructor(stepFn: Reducer); ['@@transducer/init'](): TResult; ['@@transducer/step'](result: TResult, input: TInput): TResult; ['@@transducer/result'](result: TResult): TResult; From d4bdb400a0e12b615c4b2bd6d138d4723cf24231 Mon Sep 17 00:00:00 2001 From: David Philipson Date: Wed, 21 Jun 2017 18:27:55 -0700 Subject: [PATCH 4/5] More general Transducer definition --- types/transducers-js/index.d.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/types/transducers-js/index.d.ts b/types/transducers-js/index.d.ts index 66073d1cbc..83dbbe1573 100644 --- a/types/transducers-js/index.d.ts +++ b/types/transducers-js/index.d.ts @@ -11,7 +11,12 @@ export interface Reduced { export type Reducer = (result: TResult, input: TInput) => TResult; -export type Transducer = (xf: Transformer) => Transformer; +// Common case: Transducer = +// Transformer => Transformer. +export type Transducer = + ( + xf: CompletingTransformer + ) => CompletingTransformer; export interface CompletingTransformer { ['@@transducer/init'](): TResult | void; From 45f22ec21e3b253c3264e2f28c8bf33a36a104bb Mon Sep 17 00:00:00 2001 From: David Philipson Date: Thu, 22 Jun 2017 18:05:21 -0700 Subject: [PATCH 5/5] Improve complement definition --- types/transducers-js/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/transducers-js/index.d.ts b/types/transducers-js/index.d.ts index 83dbbe1573..96fce6f671 100644 --- a/types/transducers-js/index.d.ts +++ b/types/transducers-js/index.d.ts @@ -47,7 +47,7 @@ export function comp(...args: Array<(x: any) => any>): (x: any) => any; /** * Take a predicate function and return its complement. */ -export function complement(f: Function): Function; +export function complement(f: (x: T) => boolean): (x: T) => boolean; /** * Identity function.