diff --git a/types/c3/tsconfig.json b/types/c3/tsconfig.json index aa923e91c0..60849b491f 100644 --- a/types/c3/tsconfig.json +++ b/types/c3/tsconfig.json @@ -11,7 +11,8 @@ "types": [], "paths": { "d3-scale": ["d3-scale/v1"], - "d3": ["d3/v4"] + "d3": ["d3/v4"], + "d3-array": ["d3-array/v1"] }, "noEmit": true, "forceConsistentCasingInFileNames": true diff --git a/types/d3-array/d3-array-tests.ts b/types/d3-array/d3-array-tests.ts index b0d00d5d20..697543830b 100644 --- a/types/d3-array/d3-array-tests.ts +++ b/types/d3-array/d3-array-tests.ts @@ -70,7 +70,7 @@ const mixedObjectArray = [ ]; const mixedObjectOrUndefinedArray = [...mixedObjectArray, undefined]; -const mixedObjectArrayLike = mixedObjectArray as ArrayLike; +const mixedObjectArrayLike = mixedObjectArray as Iterable; let typedArray = Uint8Array.from(numbersArray); let readonlyNumbersArray = numbersArray as ReadonlyArray; @@ -81,55 +81,55 @@ const readonlyDateArray = dateArray as ReadonlyArray; const readonlyMixedObjectArray = mixedObjectArray as ReadonlyArray; const readonlyMixedObjectOrUndefinedArray = mixedObjectOrUndefinedArray as ReadonlyArray; -function accessorMixedObjectToNum(datum: MixedObject, index: number, array: ArrayLike): number { +function accessorMixedObjectToNum(datum: MixedObject, index: number, array: Iterable): number { return datum.num; } -function accessorMixedObjectToStr(datum: MixedObject, index: number, array: ArrayLike): string { +function accessorMixedObjectToStr(datum: MixedObject, index: number, array: Iterable): string { return datum.str; } -function accessorMixedObjectToNumeric(datum: MixedObject, index: number, array: ArrayLike): NumCoercible { +function accessorMixedObjectToNumeric(datum: MixedObject, index: number, array: Iterable): NumCoercible { return datum.numeric; } -function accessorMixedObjectToDate(datum: MixedObject, index: number, array: ArrayLike): Date { +function accessorMixedObjectToDate(datum: MixedObject, index: number, array: Iterable): Date { return datum.date; } -function accessorMixedObjectToNumOrUndefined(datum: MixedObject | undefined, index: number, array: ArrayLike): number | undefined | null { +function accessorMixedObjectToNumOrUndefined(datum: MixedObject | undefined, index: number, array: Iterable): number | undefined | null { return datum ? datum.num : undefined; } -function accessorMixedObjectToStrOrUndefined(datum: MixedObject | undefined, index: number, array: ArrayLike): string | undefined | null { +function accessorMixedObjectToStrOrUndefined(datum: MixedObject | undefined, index: number, array: Iterable): string | undefined | null { return datum ? datum.str : undefined; } -function accessorLikeMixedObjectToNum(datum: MixedObject, index: number, array: ArrayLike): number { +function accessorLikeMixedObjectToNum(datum: MixedObject, index: number, array: Iterable): number { return datum.num; } -function accessorLikeMixedObjectToStr(datum: MixedObject, index: number, array: ArrayLike): string { +function accessorLikeMixedObjectToStr(datum: MixedObject, index: number, array: Iterable): string { return datum.str; } -function accessorLikeMixedObjectToNumeric(datum: MixedObject, index: number, array: ArrayLike): NumCoercible { +function accessorLikeMixedObjectToNumeric(datum: MixedObject, index: number, array: Iterable): NumCoercible { return datum.numeric; } -function accessorLikeMixedObjectToDate(datum: MixedObject, index: number, array: ArrayLike): Date { +function accessorLikeMixedObjectToDate(datum: MixedObject, index: number, array: Iterable): Date { return datum.date; } -function accessorLikeMixedObjectToNumOrUndefined(datum: MixedObject | undefined, index: number, array: ArrayLike): number | undefined | null { +function accessorLikeMixedObjectToNumOrUndefined(datum: MixedObject | undefined, index: number, array: Iterable): number | undefined | null { return datum ? datum.num : undefined; } -function accessorLikeMixedObjectToStrOrUndefined(datum: MixedObject | undefined, index: number, array: ArrayLike): string | undefined | null { +function accessorLikeMixedObjectToStrOrUndefined(datum: MixedObject | undefined, index: number, array: Iterable): string | undefined | null { return datum ? datum.str : undefined; } -function accessorReadOnlyMixedObjectToNumOrUndefined(datum: MixedObject | undefined, index: number, array: ArrayLike): number | undefined | null { +function accessorReadOnlyMixedObjectToNumOrUndefined(datum: MixedObject | undefined, index: number, array: Iterable): number | undefined | null { return datum ? datum.num : undefined; } @@ -485,6 +485,12 @@ num = mixedObjectDateBisectorObject.right(readonlyMixedObjectArray, new Date(201 num = mixedObjectDateBisectorObject.right(readonlyMixedObjectArray, new Date(2015, 3, 14), 1); num = mixedObjectDateBisectorObject.right(readonlyMixedObjectArray, new Date(2015, 3, 14), 3, 4); +// quickselect +numbersArray = d3Array.quickselect(numbersArray, 3); +numbersArray = d3Array.quickselect(numbersArray, 3, 0); +numbersArray = d3Array.quickselect(numbersArray, 3, 0, 5); +numbersArray = d3Array.quickselect(numbersArray, 3, 0, 5, d3Array.descending); + // ascending() ----------------------------------------------------------------- num = d3Array.ascending(undefined, 20); @@ -536,6 +542,23 @@ mergedArray = d3Array.merge([testArray1, [15, 30]]); // fails, type mismatch mergedArray = d3Array.merge(readonlyTestArrays); // inferred type mergedArray = d3Array.merge(readonlyTestArrays); // explicit type +interface ObjDefinition { + name: string; + amount: string; + date: string; +} + +const objArray: ObjDefinition[] = [ + { name: "jim", amount: "34.0", date: "11/12/2015" }, + { name: "carl", amount: "120.11", date: "11/12/2015" }, + { name: "stacy", amount: "12.01", date: "01/04/2016" }, + { name: "stacy", amount: "34.05", date: "01/04/2016" } +]; + +const grouped: Map = d3Array.group(objArray, d => d.name); +const rolledup: Map = d3Array.rollup(objArray, d => d.length, d => d.name); +const rolledup2: Map = d3Array.rollup(objArray, d => d.map(u => u.name).join(' '), d => d.name); + // cross() --------------------------------------------------------------------- let crossed: Array<[string, number]>; @@ -780,7 +803,7 @@ histoMixedObject_Date = histoMixedObject_Date.domain(timeScale.domain()); // fai domainFnDate = histoMixedObject_Date.domain(); histoMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined.domain([new Date(2014, 3, 15), new Date(2017, 4, 15)]); histoMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined.domain([domain[0], domain[domain.length]]); -histoMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined.domain((values) => [values[0]!, values[values.length]!]); +histoMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined.domain((values) => [values[0]!, values[values.length]!]); // thresholds(...) ------------------------------------------------------------- @@ -935,8 +958,3 @@ num = d3Array.thresholdScott(readonlyNumbersArray, -1, 234); num = d3Array.thresholdSturges(numbersArray); num = d3Array.thresholdSturges(typedArray); num = d3Array.thresholdSturges(readonlyNumbersArray); - -// Deprecated ================================================================== - -const histDeprecatedNumber: d3Array.HistogramGenerator = d3Array.histogram(); -const histDeprecatedDate: d3Array.HistogramGenerator = d3Array.histogram(); diff --git a/types/d3-array/index.d.ts b/types/d3-array/index.d.ts index 16a0e659cb..5de77e4e10 100644 --- a/types/d3-array/index.d.ts +++ b/types/d3-array/index.d.ts @@ -1,13 +1,14 @@ -// Type definitions for D3JS d3-array module 1.2 +// Type definitions for D3JS d3-array module 2.0 // Project: https://github.com/d3/d3-array, https://d3js.org/d3-array // Definitions by: Alex Ford // Boris Yankov // Tom Wanzek -// denisname +// denisname , +// Hugues Stefanski // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.3 -// Last module patch version validated against: 1.2.1 +// Last module patch version validated against: 2.0.3 // -------------------------------------------------------------------------- // Shared Types and Interfaces @@ -32,128 +33,128 @@ export interface Numeric { /** * Return the maximum value in the array of strings using natural order. */ -export function max(array: ArrayLike): string | undefined; +export function max(array: Iterable): string | undefined; /** * Return the maximum value in the array of numbers using natural order. */ -export function max(array: ArrayLike): T | undefined; +export function max(array: Iterable): T | undefined; /** * Return the maximum value in the array using natural order and a projection function to map values to strings. */ -export function max(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => string | undefined | null): string | undefined; +export function max(array: Iterable, accessor: (datum: T, index: number, array: Iterable) => string | undefined | null): string | undefined; /** * Return the maximum value in the array using natural order and a projection function to map values to easily-sorted values. */ -export function max(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => U | undefined | null): U | undefined; +export function max(array: Iterable, accessor: (datum: T, index: number, array: Iterable) => U | undefined | null): U | undefined; /** * Return the minimum value in the array using natural order. */ -export function min(array: ArrayLike): string | undefined; +export function min(array: Iterable): string | undefined; /** * Return the minimum value in the array using natural order. */ -export function min(array: ArrayLike): T | undefined; +export function min(array: Iterable): T | undefined; /** * Return the minimum value in the array using natural order. */ -export function min(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => string | undefined | null): string | undefined; +export function min(array: Iterable, accessor: (datum: T, index: number, array: Iterable) => string | undefined | null): string | undefined; /** * Return the minimum value in the array using natural order. */ -export function min(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => U | undefined | null): U | undefined; +export function min(array: Iterable, accessor: (datum: T, index: number, array: Iterable) => U | undefined | null): U | undefined; /** * Return the min and max simultaneously. */ -export function extent(array: ArrayLike): [string, string] | [undefined, undefined]; +export function extent(array: Iterable): [string, string] | [undefined, undefined]; /** * Return the min and max simultaneously. */ -export function extent(array: ArrayLike): [T, T] | [undefined, undefined]; +export function extent(array: Iterable): [T, T] | [undefined, undefined]; /** * Return the min and max simultaneously. */ -export function extent(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => string | undefined | null): [string, string] | [undefined, undefined]; +export function extent(array: Iterable, accessor: (datum: T, index: number, array: Iterable) => string | undefined | null): [string, string] | [undefined, undefined]; /** * Return the min and max simultaneously. */ -export function extent(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => U | undefined | null): [U, U] | [undefined, undefined]; +export function extent(array: Iterable, accessor: (datum: T, index: number, array: Iterable) => U | undefined | null): [U, U] | [undefined, undefined]; /** * Return the mean of an array of numbers */ -export function mean(array: ArrayLike): number | undefined; +export function mean(array: Iterable): number | undefined; /** * Return the mean of an array of numbers */ -export function mean(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => number | undefined | null): number | undefined; +export function mean(array: Iterable, accessor: (datum: T, index: number, array: Iterable) => number | undefined | null): number | undefined; /** * Return the median of an array of numbers */ -export function median(array: ArrayLike): number | undefined; +export function median(array: Iterable): number | undefined; /** * Return the median of an array of numbers */ -export function median(array: ArrayLike, accessor: (element: T, i: number, array: ArrayLike) => number | undefined | null): number | undefined; +export function median(array: Iterable, accessor: (element: T, i: number, array: Iterable) => number | undefined | null): number | undefined; /** * Returns the p-quantile of an array of numbers */ -export function quantile(array: ArrayLike, p: number): number | undefined; +export function quantile(array: Iterable, p: number): number | undefined; -export function quantile(array: ArrayLike, p: number, accessor: (element: T, i: number, array: ArrayLike) => number | undefined | null): number | undefined; +export function quantile(array: Iterable, p: number, accessor: (element: T, i: number, array: Iterable) => number | undefined | null): number | undefined; /** * Compute the sum of an array of numbers. */ -export function sum(array: ArrayLike): number; +export function sum(array: Iterable): number; /** * Compute the sum of an array, using the given accessor to convert values to numbers. */ -export function sum(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => number | undefined | null): number; +export function sum(array: Iterable, accessor: (datum: T, index: number, array: Iterable) => number | undefined | null): number; /** * Compute the standard deviation, defined as the square root of the bias-corrected variance, of the given array of numbers. */ -export function deviation(array: ArrayLike): number | undefined; +export function deviation(array: Iterable): number | undefined; /** * Compute the standard deviation, defined as the square root of the bias-corrected variance, of the given array, * using the given accessor to convert values to numbers. */ -export function deviation(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => number | undefined | null): number | undefined; +export function deviation(array: Iterable, accessor: (datum: T, index: number, array: Iterable) => number | undefined | null): number | undefined; /** * Compute an unbiased estimator of the population variance of the given array of numbers. */ -export function variance(array: ArrayLike): number | undefined; +export function variance(array: Iterable): number | undefined; /** * Compute an unbiased estimator of the population variance of the given array, * using the given accessor to convert values to numbers. */ -export function variance(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => number | undefined | null): number | undefined; +export function variance(array: Iterable, accessor: (datum: T, index: number, array: Iterable) => number | undefined | null): number | undefined; // -------------------------------------------------------------------------------------- // Searching Arrays // -------------------------------------------------------------------------------------- -export function scan(array: ArrayLike, comparator?: (a: number, b: number) => number): number | undefined; -export function scan(array: ArrayLike, comparator: (a: T, b: T) => number): number | undefined; +export function scan(array: Iterable, comparator?: (a: number, b: number) => number): number | undefined; +export function scan(array: Iterable, comparator: (a: T, b: T) => number): number | undefined; export function bisectLeft(array: ArrayLike, x: number, lo?: number, hi?: number): number; export function bisectLeft(array: ArrayLike, x: string, lo?: number, hi?: number): number; @@ -173,6 +174,44 @@ export interface Bisector { export function bisector(comparator: (a: T, b: U) => number): Bisector; export function bisector(accessor: (x: T) => U): Bisector; +/** + * Rearranges items so that all items in the [left, k] are the smallest. The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @param array The array to partially sort (in place). + * @param k The middle index for partial sorting. + */ +export function quickselect(array: ArrayLike, k: number): T[]; + +/** + * Rearranges items so that all items in the [left, k] are the smallest. The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @param array The array to partially sort (in place). + * @param k The middle index for partial sorting. + * @param left The left index of the range to sort. + */ +export function quickselect(array: ArrayLike, k: number, left: number): T[]; + +/** + * Rearranges items so that all items in the [left, k] are the smallest. The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @param array The array to partially sort (in place). + * @param k The middle index for partial sorting. + * @param left The left index of the range to sort. + * @param right The right index. + */ +export function quickselect(array: ArrayLike, k: number, left: number, right: number): T[]; + +/** + * Rearranges items so that all items in the [left, k] are the smallest. The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @param array The array to partially sort (in place). + * @param k The middle index for partial sorting. + * @param left The left index of the range to sort. + * @param right The right index. + * @param compare The compare function. + */ +export function quickselect(array: ArrayLike, k: number, left: number, right: number, compare: (a: Primitive | undefined, b: Primitive | undefined) => number): T[]; + // NB. this is limited to primitive values due to D3's use of the <, >, and >= operators. Results get weird for object instances. /** * Compares two primitive values for sorting (in ascending order). @@ -189,6 +228,22 @@ export function descending(a: Primitive | undefined, b: Primitive | undefined): // Transforming Arrays // -------------------------------------------------------------------------------------- +/** + * Groups the specified array of values into a Map from key to array of value. + * @param a The array to group. + * @param key The key function. + */ +export function group(a: Iterable, key: (value: TObject) => TKey): Map; + +/** + * Groups and reduces the specified array of values into a Map from key to value. + * + * @param a The array to group. + * @param reduce The reduce function. + * @param key The key function. + */ +export function rollup(a: Iterable, reduce: (value: TObject[]) => TReduce, key: (value: TObject) => TKey): Map; + /** * Returns the Cartesian product of the two arrays a and b. * For each element i in the specified array a and each element j in the specified array b, in order, @@ -197,7 +252,7 @@ export function descending(a: Primitive | undefined, b: Primitive | undefined): * @param a First input array. * @param b Second input array. */ -export function cross(a: ArrayLike, b: ArrayLike): Array<[S, T]>; +export function cross(a: Iterable, b: Iterable): Array<[S, T]>; /** * Returns the Cartesian product of the two arrays a and b. @@ -208,12 +263,12 @@ export function cross(a: ArrayLike, b: ArrayLike): Array<[S, T]>; * @param b Second input array. * @param reducer A reducer function taking as input an element from "a" and "b" and returning a reduced value. */ -export function cross(a: ArrayLike, b: ArrayLike, reducer: (a: S, b: T) => U): U[]; +export function cross(a: Iterable, b: Iterable, reducer: (a: S, b: T) => U): U[]; /** * Merges the specified arrays into a single array. */ -export function merge(arrays: ArrayLike>): T[]; +export function merge(arrays: Iterable>): T[]; /** * For each adjacent pair of elements in the specified array, returns a new array of tuples of elements i and i - 1. @@ -221,7 +276,7 @@ export function merge(arrays: ArrayLike>): T[]; * * @param array Array of input elements */ -export function pairs(array: ArrayLike): Array<[T, T]>; +export function pairs(array: Iterable): Array<[T, T]>; /** * For each adjacent pair of elements in the specified array, in order, invokes the specified reducer function passing the element i and element i - 1. * Returns the resulting array of pair-wise reduced elements. @@ -230,7 +285,7 @@ export function pairs(array: ArrayLike): Array<[T, T]>; * @param array Array of input elements * @param reducer A reducer function taking as input to adjacent elements of the input array and returning a reduced value. */ -export function pairs(array: ArrayLike, reducer: (a: T, b: T) => U): U[]; +export function pairs(array: Iterable, reducer: (a: T, b: T) => U): U[]; /** * Returns a permutation of the specified array using the specified array of indexes. @@ -351,36 +406,6 @@ export type ThresholdNumberArrayGenerator = export type ThresholdDateArrayGenerator = (values: ArrayLike, min: Date, max: Date) => Value[]; -/** - * @deprecated Use ThresholdNumberArrayGenerator or ThresholdDateArrayGenerator. - */ -export type ThresholdArrayGenerator = ThresholdNumberArrayGenerator; - -/** - * @deprecated Use `HistogramGeneratorNumber` for `number` values and `HistogramGeneratorDate for `Date` values. - */ -export interface HistogramGenerator { - (data: ArrayLike): Array>; - - value(): (d: Datum, i: number, data: ArrayLike) => Value; - value(valueAccessor: (d: Datum, i: number, data: ArrayLike) => Value): this; - - domain(): (values: ArrayLike) => [Value, Value] | [undefined, undefined]; - domain(domain: [Value, Value]): this; - domain(domainAccessor: (values: ArrayLike) => [Value, Value] | [undefined, undefined]): this; - - /** - * Set the array of values to be used as thresholds in determining the bins. - * - * Any threshold values outside the domain are ignored. The first bin.x0 is always equal to the minimum domain value, - * and the last bin.x1 is always equal to the maximum domain value. - * - * @param thresholds Array of threshold values used for binning. The elements must - * be of the same type as the materialized values of the histogram. - */ - thresholds(thresholds: ArrayLike): this; -} - export interface HistogramCommon { (data: ArrayLike): Array>; @@ -419,9 +444,9 @@ export interface HistogramGeneratorDate e } export interface HistogramGeneratorNumber extends HistogramCommon { - domain(): (values: ArrayLike) => [number, number] | [undefined, undefined]; + domain(): (values: Iterable) => [number, number] | [undefined, undefined]; domain(domain: [number, number]): this; - domain(domainAccessor: (values: ArrayLike) => [number, number] | [undefined, undefined]): this; + domain(domainAccessor: (values: Iterable) => [number, number] | [undefined, undefined]): this; thresholds(): ThresholdCountGenerator | ThresholdNumberArrayGenerator; /** @@ -475,12 +500,6 @@ export function histogram(): HistogramGeneratorNumber; export function histogram(): HistogramGeneratorNumber; export function histogram(): HistogramGeneratorDate; -/** - * @deprecated Do not use Value generic which mixes number and Date types. Use either number or Date - * (in combination with undefined, as applicable) to obtain a type-specific histogram generator. - */ -export function histogram(): HistogramGenerator; - // -------------------------------------------------------------------------------------- // Histogram Thresholds // -------------------------------------------------------------------------------------- diff --git a/types/d3-array/v1/d3-array-tests.ts b/types/d3-array/v1/d3-array-tests.ts new file mode 100644 index 0000000000..01529191b8 --- /dev/null +++ b/types/d3-array/v1/d3-array-tests.ts @@ -0,0 +1,941 @@ +/** + * Typescript definition tests for d3/d3-array module + * + * Note: These tests are intended to test the definitions only + * in the sense of typing and call signature consistency. They + * are not intended as functional tests. + */ + +import * as d3Array from 'd3-array'; +import { scaleTime } from 'd3-scale'; +import { timeYear } from 'd3-time'; + +// ----------------------------------------------------------------------------- +// Preparatory Steps +// ----------------------------------------------------------------------------- + +class NumCoercible { + a: number; + + constructor(a: number) { + this.a = a; + } + valueOf() { + return this.a; + } +} + +class MixedObject { + num: number; + str: string; + numeric: NumCoercible; + date: Date; + + constructor(a: number, date: Date) { + this.num = a; + this.str = a.toString(); + this.numeric = new NumCoercible(a); + this.date = date; + } +} + +let num: number; +let undef: undefined; +let mixedObject: MixedObject; + +let numOrUndefined: number | undefined; +let strOrUndefined: string | undefined; +let numericOrUndefined: NumCoercible | undefined; +let dateOrUndefined: Date | undefined; +let mixedObjectOrUndefined: MixedObject | undefined; +let numOrUndefinedExtent: [number, number] | [undefined, undefined]; +let strOrUndefinedExtent: [string, string] | [undefined, undefined]; +let numericOrUndefinedExtent: [NumCoercible, NumCoercible] | [undefined, undefined]; +let dateMixedOrUndefined: [Date, Date] | [undefined, undefined]; +let mixedOrUndefinedExtent: [d3Array.Primitive | NumCoercible, d3Array.Primitive | NumCoercible] | [undefined, undefined]; +let dateOrUndefinedExtent: [Date, Date] | [undefined, undefined]; + +let numbersArray = [10, 20, 30, 40, 50]; +const numbersOrUndefinedArray = [10, 20, undefined, null, 40, 50]; +let stringyNumbersArray = ['10', '20', '30', '40', '50']; +const numericArray = [new NumCoercible(10), new NumCoercible(20), new NumCoercible(30), new NumCoercible(40), new NumCoercible(50)]; +let dateArray = [new Date(2016, 6, 1), new Date(2016, 7, 30), new Date(2015, 3, 15)]; + +const mixedObjectArray = [ + new MixedObject(10, new Date(2016, 6, 1)), + new MixedObject(20, new Date(2016, 7, 30)), + new MixedObject(30, new Date(2015, 3, 15)), + new MixedObject(40, new Date(2014, 3, 15)), + new MixedObject(50, new Date(2017, 4, 15)) +]; + +const mixedObjectOrUndefinedArray = [...mixedObjectArray, undefined]; +const mixedObjectArrayLike = mixedObjectArray as ArrayLike; + +let typedArray = Uint8Array.from(numbersArray); +let readonlyNumbersArray = numbersArray as ReadonlyArray; +const readonlyNumbersOrUndefinedArray = numbersOrUndefinedArray as ReadonlyArray; +const readonlyStringyNumbersArray = stringyNumbersArray as ReadonlyArray; +const readonlyNumericArray = numericArray as ReadonlyArray; +const readonlyDateArray = dateArray as ReadonlyArray; +const readonlyMixedObjectArray = mixedObjectArray as ReadonlyArray; +const readonlyMixedObjectOrUndefinedArray = mixedObjectOrUndefinedArray as ReadonlyArray; + +function accessorMixedObjectToNum(datum: MixedObject, index: number, array: ArrayLike): number { + return datum.num; +} + +function accessorMixedObjectToStr(datum: MixedObject, index: number, array: ArrayLike): string { + return datum.str; +} + +function accessorMixedObjectToNumeric(datum: MixedObject, index: number, array: ArrayLike): NumCoercible { + return datum.numeric; +} + +function accessorMixedObjectToDate(datum: MixedObject, index: number, array: ArrayLike): Date { + return datum.date; +} + +function accessorMixedObjectToNumOrUndefined(datum: MixedObject | undefined, index: number, array: ArrayLike): number | undefined | null { + return datum ? datum.num : undefined; +} + +function accessorMixedObjectToStrOrUndefined(datum: MixedObject | undefined, index: number, array: ArrayLike): string | undefined | null { + return datum ? datum.str : undefined; +} + +function accessorLikeMixedObjectToNum(datum: MixedObject, index: number, array: ArrayLike): number { + return datum.num; +} + +function accessorLikeMixedObjectToStr(datum: MixedObject, index: number, array: ArrayLike): string { + return datum.str; +} + +function accessorLikeMixedObjectToNumeric(datum: MixedObject, index: number, array: ArrayLike): NumCoercible { + return datum.numeric; +} + +function accessorLikeMixedObjectToDate(datum: MixedObject, index: number, array: ArrayLike): Date { + return datum.date; +} + +function accessorLikeMixedObjectToNumOrUndefined(datum: MixedObject | undefined, index: number, array: ArrayLike): number | undefined | null { + return datum ? datum.num : undefined; +} + +function accessorLikeMixedObjectToStrOrUndefined(datum: MixedObject | undefined, index: number, array: ArrayLike): string | undefined | null { + return datum ? datum.str : undefined; +} + +function accessorReadOnlyMixedObjectToNumOrUndefined(datum: MixedObject | undefined, index: number, array: ArrayLike): number | undefined | null { + return datum ? datum.num : undefined; +} + +// ----------------------------------------------------------------------------- +// Test Statistics +// ----------------------------------------------------------------------------- + +// max() ----------------------------------------------------------------------- + +// without accessors + +numOrUndefined = d3Array.max(numbersArray); +strOrUndefined = d3Array.max(stringyNumbersArray); +numericOrUndefined = d3Array.max(numericArray); +dateOrUndefined = d3Array.max(dateArray); + +// ArrayLike test cases + +numOrUndefined = d3Array.max(typedArray); +numOrUndefined = d3Array.max(readonlyNumbersOrUndefinedArray); +strOrUndefined = d3Array.max(readonlyStringyNumbersArray); +numericOrUndefined = d3Array.max(readonlyNumericArray); +dateOrUndefined = d3Array.max(readonlyDateArray); + +// with accessors + +numOrUndefined = d3Array.max(mixedObjectArray, accessorMixedObjectToNum); +strOrUndefined = d3Array.max(mixedObjectArray, accessorMixedObjectToStr); +numericOrUndefined = d3Array.max(mixedObjectArray, accessorMixedObjectToNumeric); +dateOrUndefined = d3Array.max(mixedObjectArray, accessorMixedObjectToDate); +numOrUndefined = d3Array.max(mixedObjectArray, accessorMixedObjectToNumOrUndefined); +strOrUndefined = d3Array.max(mixedObjectArray, accessorMixedObjectToStrOrUndefined); +numOrUndefined = d3Array.max(readonlyMixedObjectOrUndefinedArray, accessorReadOnlyMixedObjectToNumOrUndefined); + +numOrUndefined = d3Array.max(mixedObjectArrayLike, accessorLikeMixedObjectToNum); +numOrUndefined = d3Array.max(mixedObjectArray, accessorLikeMixedObjectToNum); +numOrUndefined = d3Array.max(mixedObjectArray, accessorReadOnlyMixedObjectToNumOrUndefined); + +numOrUndefined = d3Array.max(mixedObjectArray, (d) => { + const l: MixedObject = d; + return l.num; +}); + +strOrUndefined = d3Array.max(mixedObjectArray, (d) => { + const l: MixedObject = d; + return l.str; +}); + +// $ExpectError +numOrUndefined = d3Array.max(readonlyNumbersArray, (d, i, a) => { a.push(3); return 0; }); + +// min() ----------------------------------------------------------------------- + +// without accessors + +numOrUndefined = d3Array.min(numbersArray); +strOrUndefined = d3Array.min(stringyNumbersArray); +numericOrUndefined = d3Array.min(numericArray); +dateOrUndefined = d3Array.min(dateArray); + +// ArrayLike test cases + +numOrUndefined = d3Array.min(typedArray); +numOrUndefined = d3Array.min(readonlyNumbersOrUndefinedArray); +strOrUndefined = d3Array.min(readonlyStringyNumbersArray); +numericOrUndefined = d3Array.min(readonlyNumericArray); +dateOrUndefined = d3Array.min(readonlyDateArray); + +// with accessors + +numOrUndefined = d3Array.min(mixedObjectArray, accessorMixedObjectToNum); +strOrUndefined = d3Array.min(mixedObjectArray, accessorMixedObjectToStr); +numericOrUndefined = d3Array.min(mixedObjectArray, accessorMixedObjectToNumeric); +dateOrUndefined = d3Array.min(mixedObjectArray, accessorMixedObjectToDate); +numOrUndefined = d3Array.min(mixedObjectArray, accessorMixedObjectToNumOrUndefined); +strOrUndefined = d3Array.min(mixedObjectArray, accessorMixedObjectToStrOrUndefined); +numOrUndefined = d3Array.min(readonlyMixedObjectOrUndefinedArray, accessorReadOnlyMixedObjectToNumOrUndefined); + +// extent() -------------------------------------------------------------------- + +// without accessors + +numOrUndefinedExtent = d3Array.extent(numbersArray); +strOrUndefinedExtent = d3Array.extent(stringyNumbersArray); +numericOrUndefinedExtent = d3Array.extent(numericArray); +dateOrUndefinedExtent = d3Array.extent(dateArray); + +// ArrayLike test cases + +numOrUndefinedExtent = d3Array.extent(typedArray); +numOrUndefinedExtent = d3Array.extent(readonlyNumbersOrUndefinedArray); +strOrUndefinedExtent = d3Array.extent(readonlyStringyNumbersArray); +numericOrUndefinedExtent = d3Array.extent(readonlyNumericArray); +dateOrUndefinedExtent = d3Array.extent(readonlyDateArray); + +// with accessors + +numOrUndefinedExtent = d3Array.extent(mixedObjectArray, accessorMixedObjectToNum); +strOrUndefinedExtent = d3Array.extent(mixedObjectArray, accessorMixedObjectToStr); +mixedOrUndefinedExtent = d3Array.extent(mixedObjectArray, accessorMixedObjectToNumeric); +dateMixedOrUndefined = d3Array.extent(mixedObjectArray, accessorMixedObjectToDate); +numOrUndefinedExtent = d3Array.extent(mixedObjectArray, accessorMixedObjectToNumOrUndefined); +strOrUndefinedExtent = d3Array.extent(mixedObjectArray, accessorMixedObjectToStrOrUndefined); +numOrUndefinedExtent = d3Array.extent(readonlyMixedObjectOrUndefinedArray, accessorReadOnlyMixedObjectToNumOrUndefined); + +// mean() ---------------------------------------------------------------------- + +numOrUndefined = d3Array.mean(numbersArray); +numOrUndefined = d3Array.mean(numericArray); +numOrUndefined = d3Array.mean(numbersOrUndefinedArray); + +numOrUndefined = d3Array.mean(typedArray); +numOrUndefined = d3Array.mean(readonlyNumbersOrUndefinedArray); +numOrUndefined = d3Array.mean(readonlyNumericArray); +numOrUndefined = d3Array.mean(readonlyNumbersOrUndefinedArray); + +numOrUndefined = d3Array.mean(mixedObjectArray, accessorMixedObjectToNum); +numOrUndefined = d3Array.mean(mixedObjectOrUndefinedArray, accessorMixedObjectToNumOrUndefined); +numOrUndefined = d3Array.mean(readonlyMixedObjectOrUndefinedArray, accessorReadOnlyMixedObjectToNumOrUndefined); + +// median() -------------------------------------------------------------------- + +numOrUndefined = d3Array.median(numbersArray); +numOrUndefined = d3Array.median(numericArray); +numOrUndefined = d3Array.median(numbersOrUndefinedArray); + +numOrUndefined = d3Array.median(typedArray); +numOrUndefined = d3Array.median(readonlyNumbersArray); +numOrUndefined = d3Array.median(readonlyNumericArray); +numOrUndefined = d3Array.median(readonlyNumbersOrUndefinedArray); + +numOrUndefined = d3Array.median(mixedObjectArray, accessorMixedObjectToNum); +numOrUndefined = d3Array.median(mixedObjectOrUndefinedArray, accessorMixedObjectToNumOrUndefined); +numOrUndefined = d3Array.median(readonlyMixedObjectOrUndefinedArray, accessorReadOnlyMixedObjectToNumOrUndefined); + +// quantile() ------------------------------------------------------------------ + +numOrUndefined = d3Array.quantile(numbersArray, 0.5); +numOrUndefined = d3Array.quantile(numericArray, 0.5); +numOrUndefined = d3Array.quantile(numbersOrUndefinedArray, 0.5); + +numOrUndefined = d3Array.quantile(typedArray, 0.5); +numOrUndefined = d3Array.quantile(readonlyNumbersArray, 0.5); +numOrUndefined = d3Array.quantile(readonlyNumericArray, 0.5); +numOrUndefined = d3Array.quantile(readonlyNumbersOrUndefinedArray, 0.5); + +numOrUndefined = d3Array.quantile(mixedObjectArray, 0.5, accessorMixedObjectToNum); +numOrUndefined = d3Array.quantile(mixedObjectOrUndefinedArray, 0.5, accessorMixedObjectToNumOrUndefined); +numOrUndefined = d3Array.quantile(readonlyMixedObjectOrUndefinedArray, 0.5, accessorReadOnlyMixedObjectToNumOrUndefined); + +// sum() ----------------------------------------------------------------------- + +numOrUndefined = d3Array.sum(numbersArray); +numOrUndefined = d3Array.sum(numericArray); +numOrUndefined = d3Array.sum(numbersOrUndefinedArray); + +numOrUndefined = d3Array.sum(typedArray); +numOrUndefined = d3Array.sum(readonlyNumbersArray); +numOrUndefined = d3Array.sum(readonlyNumericArray); +numOrUndefined = d3Array.sum(readonlyNumbersOrUndefinedArray); + +numOrUndefined = d3Array.sum(mixedObjectArray, accessorMixedObjectToNum); +numOrUndefined = d3Array.sum(mixedObjectOrUndefinedArray, accessorMixedObjectToNumOrUndefined); +numOrUndefined = d3Array.sum(readonlyMixedObjectOrUndefinedArray, accessorReadOnlyMixedObjectToNumOrUndefined); + +// deviation() ----------------------------------------------------------------- + +numOrUndefined = d3Array.deviation(numbersArray); +numOrUndefined = d3Array.deviation(numericArray); +numOrUndefined = d3Array.deviation(numbersOrUndefinedArray); + +numOrUndefined = d3Array.deviation(typedArray); +numOrUndefined = d3Array.deviation(readonlyNumbersArray); +numOrUndefined = d3Array.deviation(readonlyNumericArray); +numOrUndefined = d3Array.deviation(readonlyNumbersOrUndefinedArray); + +numOrUndefined = d3Array.deviation(mixedObjectArray, accessorMixedObjectToNum); +numOrUndefined = d3Array.deviation(mixedObjectOrUndefinedArray, accessorMixedObjectToNumOrUndefined); +numOrUndefined = d3Array.deviation(readonlyMixedObjectOrUndefinedArray, accessorReadOnlyMixedObjectToNumOrUndefined); + +// variance() ------------------------------------------------------------------ + +numOrUndefined = d3Array.variance(numbersArray); +numOrUndefined = d3Array.variance(numericArray); +numOrUndefined = d3Array.variance(numbersOrUndefinedArray); + +numOrUndefined = d3Array.variance(typedArray); +numOrUndefined = d3Array.variance(readonlyNumbersArray); +numOrUndefined = d3Array.variance(readonlyNumericArray); +numOrUndefined = d3Array.variance(readonlyNumbersOrUndefinedArray); + +numOrUndefined = d3Array.variance(mixedObjectArray, accessorMixedObjectToNum); +numOrUndefined = d3Array.variance(mixedObjectOrUndefinedArray, accessorMixedObjectToNumOrUndefined); +numOrUndefined = d3Array.variance(readonlyMixedObjectOrUndefinedArray, accessorReadOnlyMixedObjectToNumOrUndefined); + +// ----------------------------------------------------------------------------- +// Test Searching Arrays +// ----------------------------------------------------------------------------- + +numbersArray = [0, 2, 3, 4, 7, 8]; +stringyNumbersArray = ['0', '2', '3', '4', '7', '8']; +dateArray = [new Date(2010, 1, 1), new Date(2011, 1, 1), new Date(2012, 1, 1), new Date(2013, 1, 1)]; +typedArray = Uint8Array.from(numbersArray); + +// scan() ---------------------------------------------------------------------- + +numOrUndefined = d3Array.scan(numbersArray); +numOrUndefined = d3Array.scan(typedArray); +numOrUndefined = d3Array.scan(readonlyNumbersArray); + +numOrUndefined = d3Array.scan(mixedObjectArray, (a, b) => { + const aElem: MixedObject = a; + const bElem: MixedObject = b; + return a.num - b.num; +}); + +numOrUndefined = d3Array.scan(readonlyMixedObjectArray, (a, b) => { + const aElem: MixedObject = a; + const bElem: MixedObject = b; + return a.num - b.num; +}); + +numOrUndefined = d3Array.scan(mixedObjectOrUndefinedArray, (a, b) => { + const aElem: MixedObject | undefined = a; + const bElem: MixedObject | undefined = b; + return a && b ? a.num - b.num : NaN; +}); + +numOrUndefined = d3Array.scan(readonlyMixedObjectOrUndefinedArray, (a, b) => { + const aElem: MixedObject | undefined = a; + const bElem: MixedObject | undefined = b; + return a && b ? a.num - b.num : NaN; +}); + +// bisectLeft() ---------------------------------------------------------------- + +num = d3Array.bisectLeft(numbersArray, 4); +num = d3Array.bisectLeft(numbersArray, 4, 1); +num = d3Array.bisectLeft(numbersArray, 4, 1, 4); + +num = d3Array.bisectLeft(stringyNumbersArray, '21'); +num = d3Array.bisectLeft(stringyNumbersArray, '21', 1); +num = d3Array.bisectLeft(stringyNumbersArray, '21', 1, 4); + +num = d3Array.bisectLeft(dateArray, new Date(2011, 2, 1)); +num = d3Array.bisectLeft(dateArray, new Date(2011, 2, 1), 1); +num = d3Array.bisectLeft(dateArray, new Date(2011, 2, 1), 1, 2); + +num = d3Array.bisectLeft(typedArray, 4); +num = d3Array.bisectLeft(typedArray, 4, 1); +num = d3Array.bisectLeft(typedArray, 4, 1, 4); + +num = d3Array.bisectLeft(readonlyNumbersArray, 4); +num = d3Array.bisectLeft(readonlyNumbersArray, 4, 1); +num = d3Array.bisectLeft(readonlyNumbersArray, 4, 1, 4); + +num = d3Array.bisectLeft(readonlyStringyNumbersArray, '21'); +num = d3Array.bisectLeft(readonlyStringyNumbersArray, '21', 1); +num = d3Array.bisectLeft(readonlyStringyNumbersArray, '21', 1, 4); + +num = d3Array.bisectLeft(readonlyDateArray, new Date(2011, 2, 1)); +num = d3Array.bisectLeft(readonlyDateArray, new Date(2011, 2, 1), 1); +num = d3Array.bisectLeft(readonlyDateArray, new Date(2011, 2, 1), 1, 2); + +// bisectRight() --------------------------------------------------------------- + +num = d3Array.bisectRight(numbersArray, 4); +num = d3Array.bisectRight(numbersArray, 4, 1); +num = d3Array.bisectRight(numbersArray, 4, 1, 4); + +num = d3Array.bisectRight(stringyNumbersArray, '21'); +num = d3Array.bisectRight(stringyNumbersArray, '21', 1); +num = d3Array.bisectRight(stringyNumbersArray, '21', 1, 4); + +num = d3Array.bisectRight(dateArray, new Date(2011, 2, 1)); +num = d3Array.bisectRight(dateArray, new Date(2011, 2, 1), 1); +num = d3Array.bisectRight(dateArray, new Date(2011, 2, 1), 1, 2); + +num = d3Array.bisectRight(typedArray, 4); +num = d3Array.bisectRight(typedArray, 4, 1); +num = d3Array.bisectRight(typedArray, 4, 1, 4); + +num = d3Array.bisectRight(readonlyNumbersArray, 4); +num = d3Array.bisectRight(readonlyNumbersArray, 4, 1); +num = d3Array.bisectRight(readonlyNumbersArray, 4, 1, 4); + +num = d3Array.bisectRight(readonlyStringyNumbersArray, '21'); +num = d3Array.bisectRight(readonlyStringyNumbersArray, '21', 1); +num = d3Array.bisectRight(readonlyStringyNumbersArray, '21', 1, 4); + +num = d3Array.bisectRight(readonlyDateArray, new Date(2011, 2, 1)); +num = d3Array.bisectRight(readonlyDateArray, new Date(2011, 2, 1), 1); +num = d3Array.bisectRight(readonlyDateArray, new Date(2011, 2, 1), 1, 2); + +// bisect() -------------------------------------------------------------------- + +num = d3Array.bisect(numbersArray, 4); +num = d3Array.bisect(numbersArray, 4, 1); +num = d3Array.bisect(numbersArray, 4, 1, 4); + +num = d3Array.bisect(stringyNumbersArray, '21'); +num = d3Array.bisect(stringyNumbersArray, '21', 1); +num = d3Array.bisect(stringyNumbersArray, '21', 1, 4); + +num = d3Array.bisect(dateArray, new Date(2011, 2, 1)); +num = d3Array.bisect(dateArray, new Date(2011, 2, 1), 1); +num = d3Array.bisect(dateArray, new Date(2011, 2, 1), 1, 2); + +num = d3Array.bisect(typedArray, 4); +num = d3Array.bisect(typedArray, 4, 1); +num = d3Array.bisect(typedArray, 4, 1, 4); + +num = d3Array.bisect(readonlyNumbersArray, 4); +num = d3Array.bisect(readonlyNumbersArray, 4, 1); +num = d3Array.bisect(readonlyNumbersArray, 4, 1, 4); + +num = d3Array.bisect(readonlyStringyNumbersArray, '21'); +num = d3Array.bisect(readonlyStringyNumbersArray, '21', 1); +num = d3Array.bisect(readonlyStringyNumbersArray, '21', 1, 4); + +num = d3Array.bisect(readonlyDateArray, new Date(2011, 2, 1)); +num = d3Array.bisect(readonlyDateArray, new Date(2011, 2, 1), 1); +num = d3Array.bisect(readonlyDateArray, new Date(2011, 2, 1), 1, 2); + +// bisector() ------------------------------------------------------------------ + +mixedObjectArray.sort((a, b) => a.date.valueOf() - b.date.valueOf()); + +let mixedObjectDateBisectorObject: d3Array.Bisector; + +// define using accessor +mixedObjectDateBisectorObject = d3Array.bisector(el => el.date); + +// define using comparator +mixedObjectDateBisectorObject = d3Array.bisector((el, x) => + el.date.valueOf() - x.valueOf()); + +// bisect left +num = mixedObjectDateBisectorObject.left(mixedObjectArray, new Date(2015, 3, 14)); +num = mixedObjectDateBisectorObject.left(mixedObjectArray, new Date(2015, 3, 14), 1); +num = mixedObjectDateBisectorObject.left(mixedObjectArray, new Date(2015, 3, 14), 3, 4); + +num = mixedObjectDateBisectorObject.left(readonlyMixedObjectArray, new Date(2015, 3, 14)); +num = mixedObjectDateBisectorObject.left(readonlyMixedObjectArray, new Date(2015, 3, 14), 1); +num = mixedObjectDateBisectorObject.left(readonlyMixedObjectArray, new Date(2015, 3, 14), 3, 4); + +// bisect right +num = mixedObjectDateBisectorObject.right(mixedObjectArray, new Date(2015, 3, 14)); +num = mixedObjectDateBisectorObject.right(mixedObjectArray, new Date(2015, 3, 14), 1); +num = mixedObjectDateBisectorObject.right(mixedObjectArray, new Date(2015, 3, 14), 3, 4); + +num = mixedObjectDateBisectorObject.right(readonlyMixedObjectArray, new Date(2015, 3, 14)); +num = mixedObjectDateBisectorObject.right(readonlyMixedObjectArray, new Date(2015, 3, 14), 1); +num = mixedObjectDateBisectorObject.right(readonlyMixedObjectArray, new Date(2015, 3, 14), 3, 4); + +// ascending() ----------------------------------------------------------------- + +num = d3Array.ascending(undefined, 20); +num = d3Array.ascending(10, 20); +num = d3Array.ascending('10', '20'); +num = d3Array.ascending(new Date(2016, 6, 13), new Date(2016, 6, 14)); + +// descending() ---------------------------------------------------------------- + +num = d3Array.descending(undefined, 20); +num = d3Array.descending(10, 20); +num = d3Array.descending('10', '20'); +num = d3Array.descending(new Date(2016, 6, 13), new Date(2016, 6, 14)); + +// ----------------------------------------------------------------------------- +// Test Transforming Arrays +// ----------------------------------------------------------------------------- + +// merge() --------------------------------------------------------------------- + +const testArray1 = [ + new MixedObject(10, new Date(2016, 6, 1)), + new MixedObject(20, new Date(2016, 7, 30)), + new MixedObject(30, new Date(2015, 3, 15)), + new MixedObject(40, new Date(2014, 3, 15)), + new MixedObject(50, new Date(2017, 4, 15)) +]; + +const testArray2 = [ + new MixedObject(40, new Date(2016, 3, 1)), + new MixedObject(50, new Date(2016, 9, 30)), +]; + +let testArrays: MixedObject[][] = [testArray1, testArray2]; + +const readonlyTestArray1 = testArray1 as ReadonlyArray; +const readonlyTestArray2 = testArray2 as ReadonlyArray; +const readonlyTestArrays = [testArray1, testArray2] as ReadonlyArray>; + +let mergedArray: MixedObject[]; + +mergedArray = d3Array.merge(testArrays); // inferred type +mergedArray = d3Array.merge(testArrays); // explicit type +// $ExpectError +mergedArray = d3Array.merge([[10, 40, 30], [15, 30]]); // fails, type mismatch +// $ExpectError +mergedArray = d3Array.merge([testArray1, [15, 30]]); // fails, type mismatch + +mergedArray = d3Array.merge(readonlyTestArrays); // inferred type +mergedArray = d3Array.merge(readonlyTestArrays); // explicit type + +// cross() --------------------------------------------------------------------- + +let crossed: Array<[string, number]>; + +const chars = ['x', 'y']; +const nums = [1, 2]; + +crossed = d3Array.cross(chars, nums); +crossed = d3Array.cross(chars, nums); + +let strArray: string[] = d3Array.cross([2, 3], [5, 6], (a, b) => (a + b) + 'px'); +strArray = d3Array.cross([2, 3], [5, 6], (a, b) => { + const aa: number = a; + const bb: number = b; + return (aa + bb) + 'px'; +}); + +const readonlyChars = chars as ReadonlyArray; +const readonlyNums = new Uint8Array(nums); + +crossed = d3Array.cross(readonlyChars, readonlyNums); +crossed = d3Array.cross(readonlyChars, readonlyNums); + +strArray = d3Array.cross([2, 3] as ReadonlyArray, new Uint8ClampedArray([5, 6]), (a, b) => (a + b) + 'px'); +strArray = d3Array.cross([2, 3] as ReadonlyArray, new Uint8ClampedArray([5, 6]), (a, b) => { + const aa: number = a; + const bb: number = b; + return (aa + bb) + 'px'; +}); + +d3Array.cross(new Uint8Array([1, 2, 3, 4, 5]), new Uint8Array([10, 20, 30, 40, 50])); + +// pairs() --------------------------------------------------------------------- + +let pairs: Array<[MixedObject, MixedObject]>; + +pairs = d3Array.pairs(mergedArray); + +numbersArray = d3Array.pairs(mergedArray, (a, b) => b.num - a.num); +numbersArray = d3Array.pairs(mergedArray, (a, b) => { + const aa: MixedObject = a; + const bb: MixedObject = b; + return bb.num - aa.num; +}); + +const readonlyMergedArray = mergedArray as ReadonlyArray; +pairs = d3Array.pairs(readonlyMergedArray); + +numbersArray = d3Array.pairs(readonlyMergedArray, (a, b) => b.num - a.num); +numbersArray = d3Array.pairs(readonlyMergedArray, (a, b) => { + const aa: MixedObject = a; + const bb: MixedObject = b; + return bb.num - aa.num; +}); + +// permute() ------------------------------------------------------------------- + +// getting a permutation of array elements +mergedArray = d3Array.permute(mergedArray, [1, 0, 2, 5, 3, 4, 6]); +mergedArray = d3Array.permute(readonlyMergedArray, [1, 0, 2, 5, 3, 4, 6]); +mergedArray = d3Array.permute(readonlyMergedArray, nums); + +// Getting an ordered array with object properties + +const testObject = { + val: 10, + name: 'Test', + when: new Date(), + more: [10, 30, 40] +}; + +const p1: Array = d3Array.permute(testObject, ['name', 'val', 'when', 'more']); +const p2: Array = d3Array.permute(testObject, ['when', 'more']); +// $ExpectError +const p3 = d3Array.permute(testObject, ['when', 'unknown']); + +// range() --------------------------------------------------------------------- + +numbersArray = d3Array.range(10); +numbersArray = d3Array.range(1, 10); +numbersArray = d3Array.range(1, 10, 0.5); + +// shuffle() ------------------------------------------------------------------- + +mergedArray = d3Array.shuffle(mergedArray); +mergedArray = d3Array.shuffle(mergedArray, 1); +mergedArray = d3Array.shuffle(mergedArray, 1, 3); +// $ExpectError +mergedArray = d3Array.shuffle(readonlyMergedArray); // fails, shuffle mutates input array in-place + +// Test each TypedArray explicitly. Can't use ArrayLike in this case because shuffle is mutable and ArrayLike would include ReadonlyArray +const resultInt8: Int8Array = d3Array.shuffle(new Int8Array(numbersArray)); +const resultUint8: Uint8Array = d3Array.shuffle(new Uint8Array(numbersArray)); +const resultUint8Clamped: Uint8ClampedArray = d3Array.shuffle(new Uint8ClampedArray(numbersArray)); +const resultInt16: Int16Array = d3Array.shuffle(new Int16Array(numbersArray)); +const resultUint6: Uint16Array = d3Array.shuffle(new Uint16Array(numbersArray)); +const resultInt32: Int32Array = d3Array.shuffle(new Int32Array(numbersArray)); +const resultUint32: Uint32Array = d3Array.shuffle(new Uint32Array(numbersArray)); +const resultFloat32: Float32Array = d3Array.shuffle(new Float32Array(numbersArray)); +const resultFloat64: Float64Array = d3Array.shuffle(new Float64Array(numbersArray)); + +// ticks() --------------------------------------------------------------------- + +numbersArray = d3Array.ticks(1, 10, 5); + +// tickIncrement() ------------------------------------------------------------------ + +let numDiff: number = d3Array.tickIncrement(1, 10, 5); + +// tickStep() ------------------------------------------------------------------ + +numDiff = d3Array.tickStep(1, 10, 5); + +// transpose() ----------------------------------------------------------------- + +testArrays = d3Array.transpose([testArray1, testArray2]); +testArrays = d3Array.transpose([readonlyTestArray1, readonlyTestArray2] as ReadonlyArray>); + +// zip() ----------------------------------------------------------------------- + +testArrays = d3Array.zip(testArray1, testArray2); +testArrays = d3Array.zip(readonlyTestArray1, readonlyTestArray2); + +// ----------------------------------------------------------------------------- +// Test Histogram +// ----------------------------------------------------------------------------- + +const timeScale = scaleTime(); + +// Create histogram generator ================================================== + +// number - number +let histoNumber_Number: d3Array.HistogramGeneratorNumber; +histoNumber_Number = d3Array.histogram(); +histoNumber_Number = d3Array.histogram(); + +// MixedObject - number | undefined +let histoMixed_NumberOrUndefined: d3Array.HistogramGeneratorNumber; +histoMixed_NumberOrUndefined = d3Array.histogram(); + +// MixedObject | undefined - number | undefined +let histoMixedOrUndefined_NumberOrUndefined: d3Array.HistogramGeneratorNumber; +histoMixedOrUndefined_NumberOrUndefined = d3Array.histogram(); + +// MixedObject | undefined - number +let histoMixedOrUndefined_Number: d3Array.HistogramGeneratorNumber; +histoMixedOrUndefined_Number = d3Array.histogram(); + +// MixedObject - Date +let histoMixedObject_Date: d3Array.HistogramGeneratorDate; +histoMixedObject_Date = d3Array.histogram(); + +// MixedObject - Date | undefined +let histoMixedObject_DateOrUndefined: d3Array.HistogramGeneratorDate; +histoMixedObject_DateOrUndefined = d3Array.histogram(); + +let defaultHistogram: d3Array.HistogramGeneratorNumber; +defaultHistogram = d3Array.histogram(); + +// Configure histogram generator =============================================== + +// value(...) ------------------------------------------------------------------ + +let valueAccessorFn: (d: MixedObject, i: number, data: MixedObject[]) => Date; +valueAccessorFn = histoMixedObject_Date.value(); + +type valueAccessor = (d: D, i: number, data: D[]) => V; + +// number - number +const valueFnNumber_Number: valueAccessor = histoNumber_Number.value(); +histoNumber_Number = histoNumber_Number.value((d: number, i: number, data: ArrayLike) => { + return d - num; +}); + +// MixedObject - number | undefined +const valueFnMixedObject_NumberOrUndefined: valueAccessor = histoMixed_NumberOrUndefined.value(); +histoMixed_NumberOrUndefined = histoMixed_NumberOrUndefined.value((d: MixedObject, i: number, data: ArrayLike) => { + return d.str === "NA" ? undefined : d.num; +}); + +// MixedObject | undefined - number | undefined +const valueFnMixedOrUndefined_NumberOrUndefined: valueAccessor = histoMixedOrUndefined_NumberOrUndefined.value(); +histoMixedOrUndefined_NumberOrUndefined = histoMixedOrUndefined_NumberOrUndefined.value((d: MixedObject | undefined, i: number, data: ArrayLike) => { + return d ? d.num : undefined; +}); + +// MixedObject | undefined - number +const valueFnMixedOrUndefined_Number: valueAccessor = histoMixedOrUndefined_Number.value(); +histoMixedOrUndefined_Number = histoMixedOrUndefined_Number.value((d: MixedObject | undefined, i: number, data: ArrayLike) => { + return d ? d.num : 0; +}); + +// MixedObject - Date +const valueFnMixedObject_Date: valueAccessor = histoMixedObject_Date.value(); +histoMixedObject_Date = histoMixedObject_Date.value((d: MixedObject, i: number, data: ArrayLike) => { + return d.date; +}); + +// MixedObject - Date | undefined +const valueFnMixedObject_DateOrUndefined: valueAccessor = histoMixedObject_DateOrUndefined.value(); +histoMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined.value((d: MixedObject, i: number, data: ArrayLike) => { + return d.date; +}); + +// domain(...) ----------------------------------------------------------------- + +const domain = timeScale.domain(); +let domainFnNumber: (array: number[]) => [number, number] | [undefined, undefined]; +let domainFnNumberOrUndef: (array: Array) => [number, number] | [undefined, undefined]; +let domainFnDate: (values: Date[]) => [Date, Date]; + +// number - number +domainFnNumber = histoNumber_Number.domain(); +histoNumber_Number = histoNumber_Number.domain([0, 100]); +histoNumber_Number = histoNumber_Number.domain(d3Array.extent); + +// MixedObject - number | undefined +domainFnNumber = histoNumber_Number.domain(); +histoMixed_NumberOrUndefined = histoMixed_NumberOrUndefined.domain([0, 100]); +histoMixed_NumberOrUndefined = histoMixed_NumberOrUndefined.domain(d3Array.extent); + +// MixedObject | undefined - number | undefined +domainFnNumberOrUndef = histoMixedOrUndefined_NumberOrUndefined.domain(); +histoMixedOrUndefined_NumberOrUndefined = histoMixedOrUndefined_NumberOrUndefined.domain([0, 100]); +histoMixedOrUndefined_NumberOrUndefined = histoMixedOrUndefined_NumberOrUndefined.domain(d3Array.extent); + +// MixedObject | undefined - number +domainFnNumber = histoMixedOrUndefined_Number.domain(); +histoMixedOrUndefined_Number = histoMixedOrUndefined_Number.domain([0, 100]); +histoMixedOrUndefined_Number = histoMixedOrUndefined_Number.domain(d3Array.extent); + +// MixedObject - Date +domainFnDate = histoMixedObject_Date.domain(); +histoMixedObject_Date = histoMixedObject_Date.domain([new Date(2014, 3, 15), new Date(2017, 4, 15)]); +histoMixedObject_Date = histoMixedObject_Date.domain([domain[0], domain[domain.length]]); +histoMixedObject_Date = histoMixedObject_Date.domain((values) => [values[0], values[values.length]]); +// $ExpectError +histoMixedObject_Date = histoMixedObject_Date.domain(timeScale.domain()); // fails, as scale domain is an array with possibly more than the two elements expected by histogram + +// MixedObject - Date | undefined +domainFnDate = histoMixedObject_Date.domain(); +histoMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined.domain([new Date(2014, 3, 15), new Date(2017, 4, 15)]); +histoMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined.domain([domain[0], domain[domain.length]]); +histoMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined.domain((values) => [values[0]!, values[values.length]!]); + +// thresholds(...) ------------------------------------------------------------- + +type thresholdsWithUndefinedCont = d3Array.ThresholdCountGenerator; +type thresholdsWithUndefinedArray = d3Array.ThresholdNumberArrayGenerator; + +let thresholds: d3Array.ThresholdCountGenerator | d3Array.ThresholdNumberArrayGenerator; +let thresholdsWithUndefined: thresholdsWithUndefinedCont | thresholdsWithUndefinedArray; +const thresholdsArray: d3Array.ThresholdNumberArrayGenerator = (x: ArrayLike) => [5, 10, 20]; + +let thresholdsDate: d3Array.ThresholdDateArrayGenerator; +let thresholdsDateOrUndefined: d3Array.ThresholdDateArrayGenerator; + +// number - number +thresholds = histoNumber_Number.thresholds(); +histoNumber_Number = histoNumber_Number.thresholds(3); +histoNumber_Number = histoNumber_Number.thresholds([5, 10, 20]); +histoNumber_Number = histoNumber_Number.thresholds(d3Array.thresholdScott); +histoNumber_Number = histoNumber_Number.thresholds(thresholdsArray); + +// MixedObject - number | undefined +thresholdsWithUndefined = histoMixed_NumberOrUndefined.thresholds(); +histoMixed_NumberOrUndefined = histoMixed_NumberOrUndefined.thresholds(3); +histoMixed_NumberOrUndefined = histoMixed_NumberOrUndefined.thresholds([5, 10, 20]); +histoMixed_NumberOrUndefined = histoMixed_NumberOrUndefined.thresholds(d3Array.thresholdScott); + +// MixedObject | undefined - number | undefined +thresholdsWithUndefined = histoMixedOrUndefined_NumberOrUndefined.thresholds(); +histoMixedOrUndefined_NumberOrUndefined = histoMixedOrUndefined_NumberOrUndefined.thresholds(3); +histoMixedOrUndefined_NumberOrUndefined = histoMixedOrUndefined_NumberOrUndefined.thresholds([5, 10, 20]); +histoMixedOrUndefined_NumberOrUndefined = histoMixedOrUndefined_NumberOrUndefined.thresholds(d3Array.thresholdScott); + +// MixedObject | undefined - number +thresholds = histoMixedOrUndefined_Number.thresholds(); +histoMixedOrUndefined_Number = histoMixedOrUndefined_Number.thresholds(5); +histoMixedOrUndefined_Number = histoMixedOrUndefined_Number.thresholds([5, 10, 20]); +histoMixedOrUndefined_Number = histoMixedOrUndefined_Number.thresholds(d3Array.thresholdSturges); + +// MixedObject - Date +thresholdsDate = histoMixedObject_Date.thresholds(); +histoMixedObject_Date = histoMixedObject_Date.thresholds([new Date(2015, 11, 15), new Date(2016, 6, 1), new Date(2016, 8, 30)]); +histoMixedObject_Date = histoMixedObject_Date.thresholds(timeScale.ticks(timeYear)); +histoMixedObject_Date = histoMixedObject_Date.thresholds((values: ArrayLike) => [new Date(2015, 11, 15), new Date(2016, 6, 1), new Date(2016, 8, 30)]); +histoMixedObject_Date = histoMixedObject_Date.thresholds((values: ArrayLike, min: Date, max: Date) => { + const thresholds: Date[] = [values[0], values[2], values[4]]; + return thresholds; +}); +// $ExpectError +histoMixedObject_Date = histoMixedObject_Date.thresholds(d3Array.thresholdScott); + +// MixedObject - Date | undefined +thresholdsDateOrUndefined = histoMixedObject_DateOrUndefined.thresholds(); +histoMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined.thresholds([new Date(2015, 11, 15), new Date(2016, 6, 1), new Date(2016, 8, 30)]); +histoMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined.thresholds(timeScale.ticks(timeYear)); +histoMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined.thresholds((values: ArrayLike, min: Date, max: Date) => { + const thresholds: Date[] = [values[0]!, new Date(2015, 11, 15), values[values.length]!]; + return thresholds; +}); + +// Use histogram generator ===================================================== + +undef = d3Array.histogram()([])[0].x0 as undefined; +undef = d3Array.histogram()([undefined])[0].x0 as undefined; + +// number - number +let binsNumber_Number: Array>; +binsNumber_Number = histoNumber_Number([-1, 0, 1, 1, 3, 20, 234]); + +let binNumber_Number: d3Array.Bin; +binNumber_Number = binsNumber_Number[0]; + +num = binNumber_Number.length; +num = binNumber_Number[0]; +numOrUndefined = binNumber_Number.x0; +numOrUndefined = binNumber_Number.x1; + +// MixedObject - number | undefined +let binsNumberMixed_NumberOrUndefined: Array>; +binsNumberMixed_NumberOrUndefined = histoMixed_NumberOrUndefined(mixedObjectArray); + +let binNumberMixed_NumberOrUndefined: d3Array.Bin; +binNumberMixed_NumberOrUndefined = binsNumberMixed_NumberOrUndefined[0]; + +num = binNumberMixed_NumberOrUndefined.length; +mixedObject = binNumberMixed_NumberOrUndefined[0]; +numOrUndefined = binNumberMixed_NumberOrUndefined.x0; +numOrUndefined = binNumberMixed_NumberOrUndefined.x1; + +// MixedObject | undefined - number | undefined +let binsNumberMixedOrUndefined_NumberOrUndefined: Array>; +binsNumberMixedOrUndefined_NumberOrUndefined = histoMixedOrUndefined_NumberOrUndefined(mixedObjectArray); + +let binNumberMixedOrUndefined_NumberOrUndefined: d3Array.Bin; +binNumberMixedOrUndefined_NumberOrUndefined = binsNumberMixedOrUndefined_NumberOrUndefined[0]; + +num = binNumberMixedOrUndefined_NumberOrUndefined.length; +mixedObjectOrUndefined = binNumberMixedOrUndefined_NumberOrUndefined[0]; +numOrUndefined = binNumberMixedOrUndefined_NumberOrUndefined.x0; +numOrUndefined = binNumberMixedOrUndefined_NumberOrUndefined.x1; + +// MixedObject | undefined - number +let binsNumberMixedOrUndefined_Number: Array>; +binsNumberMixedOrUndefined_Number = histoMixedOrUndefined_Number(mixedObjectArray); + +let binNumberMixedOrUndefined_Number: d3Array.Bin; +binNumberMixedOrUndefined_Number = binsNumberMixedOrUndefined_Number[0]; + +num = binNumberMixedOrUndefined_Number.length; +mixedObjectOrUndefined = binNumberMixedOrUndefined_Number[0]; +numOrUndefined = binNumberMixedOrUndefined_Number.x0; +numOrUndefined = binNumberMixedOrUndefined_Number.x1; + +// MixedObject - Date +let binsMixedObject_Date: Array>; +binsMixedObject_Date = histoMixedObject_Date(mixedObjectArray); +binsMixedObject_Date = histoMixedObject_Date(readonlyMixedObjectArray); + +let binMixedObject_Date: d3Array.Bin; +binMixedObject_Date = binsMixedObject_Date[0]; + +num = binMixedObject_Date.length; +mixedObject = binMixedObject_Date[0]; +dateOrUndefined = binMixedObject_Date.x0; +dateOrUndefined = binMixedObject_Date.x1; + +// MixedObject - Date | undefined +let binsMixedObject_DateOrUndefined: Array>; +binsMixedObject_DateOrUndefined = histoMixedObject_DateOrUndefined(mixedObjectArray); + +let binMixedObject_DateOrUndefined: d3Array.Bin; +binMixedObject_DateOrUndefined = binsMixedObject_DateOrUndefined[0]; + +num = binMixedObject_DateOrUndefined.length; +mixedObject = binMixedObject_DateOrUndefined[0]; +dateOrUndefined = binMixedObject_DateOrUndefined.x0; +dateOrUndefined = binMixedObject_DateOrUndefined.x1; + +// Histogram Thresholds ======================================================== + +numbersArray = [-1, 0, 1, 1, 3, 20, 234]; +typedArray = new Uint8Array(numbersArray); +readonlyNumbersArray = numbersArray as ReadonlyArray; + +num = d3Array.thresholdFreedmanDiaconis(numbersArray, -1, 234); +num = d3Array.thresholdFreedmanDiaconis(typedArray, -1, 234); +num = d3Array.thresholdFreedmanDiaconis(readonlyNumbersArray, -1, 234); + +num = d3Array.thresholdScott(numbersArray, -1, 234); +num = d3Array.thresholdScott(typedArray, -1, 234); +num = d3Array.thresholdScott(readonlyNumbersArray, -1, 234); + +num = d3Array.thresholdSturges(numbersArray); +num = d3Array.thresholdSturges(typedArray); +num = d3Array.thresholdSturges(readonlyNumbersArray); + +// Deprecated ================================================================== + +const histDeprecatedNumber: d3Array.HistogramGenerator = d3Array.histogram(); +const histDeprecatedDate: d3Array.HistogramGenerator = d3Array.histogram(); diff --git a/types/d3-array/v1/index.d.ts b/types/d3-array/v1/index.d.ts new file mode 100644 index 0000000000..7320e1c223 --- /dev/null +++ b/types/d3-array/v1/index.d.ts @@ -0,0 +1,547 @@ +// Type definitions for D3JS d3-array module 1.2 +// Project: https://github.com/d3/d3-array +// Definitions by: Alex Ford +// Boris Yankov +// Tom Wanzek +// denisname , +// Hugues Stefanski +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.3 + +// Last module patch version validated against: 1.2.1 + +// -------------------------------------------------------------------------- +// Shared Types and Interfaces +// -------------------------------------------------------------------------- + +/** + * Administrivia: JavaScript primitive types and Date + */ +export type Primitive = number | string | boolean | Date; + +/** + * Administrivia: anything with a valueOf(): number method is comparable, so we allow it in numeric operations + */ +export interface Numeric { + valueOf(): number; +} + +// -------------------------------------------------------------------------------------- +// Descriptive Statistics +// -------------------------------------------------------------------------------------- + +/** + * Return the maximum value in the array of strings using natural order. + */ +export function max(array: ArrayLike): string | undefined; + +/** + * Return the maximum value in the array of numbers using natural order. + */ +export function max(array: ArrayLike): T | undefined; + +/** + * Return the maximum value in the array using natural order and a projection function to map values to strings. + */ +export function max(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => string | undefined | null): string | undefined; + +/** + * Return the maximum value in the array using natural order and a projection function to map values to easily-sorted values. + */ +export function max(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => U | undefined | null): U | undefined; + +/** + * Return the minimum value in the array using natural order. + */ +export function min(array: ArrayLike): string | undefined; + +/** + * Return the minimum value in the array using natural order. + */ +export function min(array: ArrayLike): T | undefined; + +/** + * Return the minimum value in the array using natural order. + */ +export function min(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => string | undefined | null): string | undefined; + +/** + * Return the minimum value in the array using natural order. + */ +export function min(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => U | undefined | null): U | undefined; + +/** + * Return the min and max simultaneously. + */ +export function extent(array: ArrayLike): [string, string] | [undefined, undefined]; + +/** + * Return the min and max simultaneously. + */ +export function extent(array: ArrayLike): [T, T] | [undefined, undefined]; + +/** + * Return the min and max simultaneously. + */ +export function extent(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => string | undefined | null): [string, string] | [undefined, undefined]; + +/** + * Return the min and max simultaneously. + */ +export function extent(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => U | undefined | null): [U, U] | [undefined, undefined]; + +/** + * Return the mean of an array of numbers + */ +export function mean(array: ArrayLike): number | undefined; + +/** + * Return the mean of an array of numbers + */ +export function mean(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => number | undefined | null): number | undefined; + +/** + * Return the median of an array of numbers + */ +export function median(array: ArrayLike): number | undefined; + +/** + * Return the median of an array of numbers + */ +export function median(array: ArrayLike, accessor: (element: T, i: number, array: ArrayLike) => number | undefined | null): number | undefined; + +/** + * Returns the p-quantile of an array of numbers + */ +export function quantile(array: ArrayLike, p: number): number | undefined; + +export function quantile(array: ArrayLike, p: number, accessor: (element: T, i: number, array: ArrayLike) => number | undefined | null): number | undefined; + +/** + * Compute the sum of an array of numbers. + */ +export function sum(array: ArrayLike): number; + +/** + * Compute the sum of an array, using the given accessor to convert values to numbers. + */ +export function sum(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => number | undefined | null): number; + +/** + * Compute the standard deviation, defined as the square root of the bias-corrected variance, of the given array of numbers. + */ +export function deviation(array: ArrayLike): number | undefined; + +/** + * Compute the standard deviation, defined as the square root of the bias-corrected variance, of the given array, + * using the given accessor to convert values to numbers. + */ +export function deviation(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => number | undefined | null): number | undefined; + +/** + * Compute an unbiased estimator of the population variance of the given array of numbers. + */ +export function variance(array: ArrayLike): number | undefined; + +/** + * Compute an unbiased estimator of the population variance of the given array, + * using the given accessor to convert values to numbers. + */ +export function variance(array: ArrayLike, accessor: (datum: T, index: number, array: ArrayLike) => number | undefined | null): number | undefined; + +// -------------------------------------------------------------------------------------- +// Searching Arrays +// -------------------------------------------------------------------------------------- + +export function scan(array: ArrayLike, comparator?: (a: number, b: number) => number): number | undefined; +export function scan(array: ArrayLike, comparator: (a: T, b: T) => number): number | undefined; + +export function bisectLeft(array: ArrayLike, x: number, lo?: number, hi?: number): number; +export function bisectLeft(array: ArrayLike, x: string, lo?: number, hi?: number): number; +export function bisectLeft(array: ArrayLike, x: Date, lo?: number, hi?: number): number; + +export function bisectRight(array: ArrayLike, x: number, lo?: number, hi?: number): number; +export function bisectRight(array: ArrayLike, x: string, lo?: number, hi?: number): number; +export function bisectRight(array: ArrayLike, x: Date, lo?: number, hi?: number): number; + +export const bisect: typeof bisectRight; + +export interface Bisector { + left(array: ArrayLike, x: U, lo?: number, hi?: number): number; + right(array: ArrayLike, x: U, lo?: number, hi?: number): number; +} + +export function bisector(comparator: (a: T, b: U) => number): Bisector; +export function bisector(accessor: (x: T) => U): Bisector; + +/** + * Rearranges items so that all items in the [left, k] are the smallest. The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @param array The array to partially sort (in place). + * @param k The middle index for partial sorting. + */ +export function quickselect(array: ArrayLike, k: number): T[]; + +/** + * Rearranges items so that all items in the [left, k] are the smallest. The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @param array The array to partially sort (in place). + * @param k The middle index for partial sorting. + * @param left The left index of the range to sort. + */ +export function quickselect(array: ArrayLike, k: number, left: number): T[]; + +/** + * Rearranges items so that all items in the [left, k] are the smallest. The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @param array The array to partially sort (in place). + * @param k The middle index for partial sorting. + * @param left The left index of the range to sort. + * @param right The right index. + */ +export function quickselect(array: ArrayLike, k: number, left: number, right: number): T[]; + +/** + * Rearranges items so that all items in the [left, k] are the smallest. The k-th element will have the (k - left + 1)-th smallest value in [left, right]. + * + * @param array The array to partially sort (in place). + * @param k The middle index for partial sorting. + * @param left The left index of the range to sort. + * @param right The right index. + * @param compare The compare function. + */ +export function quickselect(array: ArrayLike, k: number, left: number, right: number, compare: (a: Primitive | undefined, b: Primitive | undefined) => number): T[]; + +// NB. this is limited to primitive values due to D3's use of the <, >, and >= operators. Results get weird for object instances. +/** + * Compares two primitive values for sorting (in ascending order). + */ +export function ascending(a: Primitive | undefined, b: Primitive | undefined): number; + +// NB. this is limited to primitive values due to D3's use of the <, >, and >= operators. Results get weird for object instances. +/** + * Compares two primitive values for sorting (in ascending order). + */ +export function descending(a: Primitive | undefined, b: Primitive | undefined): number; + +// -------------------------------------------------------------------------------------- +// Transforming Arrays +// -------------------------------------------------------------------------------------- + +/** + * Groups the specified array of values into a Map from key to array of value. + * @param a The array to group. + * @param key The key function. + */ +export function group(a: ArrayLike, key: (value: TObject) => TKey): Map; + +/** + * Groups and reduces the specified array of values into a Map from key to value. + * + * @param a The array to group. + * @param reduce The reduce function. + * @param key The key function. + */ +export function rollup(a: ArrayLike, reduce: (value: TObject[]) => TReduce, key: (value: TObject) => TKey): Map; + +/** + * Returns the Cartesian product of the two arrays a and b. + * For each element i in the specified array a and each element j in the specified array b, in order, + * it creates a two-element array for each pair. + * + * @param a First input array. + * @param b Second input array. + */ +export function cross(a: ArrayLike, b: ArrayLike): Array<[S, T]>; + +/** + * Returns the Cartesian product of the two arrays a and b. + * For each element i in the specified array a and each element j in the specified array b, in order, + * invokes the specified reducer function passing the element i and element j. + * + * @param a First input array. + * @param b Second input array. + * @param reducer A reducer function taking as input an element from "a" and "b" and returning a reduced value. + */ +export function cross(a: ArrayLike, b: ArrayLike, reducer: (a: S, b: T) => U): U[]; + +/** + * Merges the specified arrays into a single array. + */ +export function merge(arrays: ArrayLike>): T[]; + +/** + * For each adjacent pair of elements in the specified array, returns a new array of tuples of elements i and i - 1. + * Returns the empty array if the input array has fewer than two elements. + * + * @param array Array of input elements + */ +export function pairs(array: ArrayLike): Array<[T, T]>; +/** + * For each adjacent pair of elements in the specified array, in order, invokes the specified reducer function passing the element i and element i - 1. + * Returns the resulting array of pair-wise reduced elements. + * Returns the empty array if the input array has fewer than two elements. + * + * @param array Array of input elements + * @param reducer A reducer function taking as input to adjacent elements of the input array and returning a reduced value. + */ +export function pairs(array: ArrayLike, reducer: (a: T, b: T) => U): U[]; + +/** + * Returns a permutation of the specified array using the specified array of indexes. + * The returned array contains the corresponding element in array for each index in indexes, in order. + * For example, `permute(["a", "b", "c"], [1, 2, 0]) // ["b", "c", "a"]` + */ +export function permute(array: { [key: number]: T }, keys: ArrayLike): T[]; + +/** + * Extract the values from an object into an array with a stable order. For example: + * `var object = {yield: 27, year: 1931, site: "University Farm"};` + * `d3.permute(object, ["site", "yield"]); // ["University Farm", 27]` + */ +export function permute(object: T, keys: ArrayLike): Array; + +/** + * Generates a 0-based numeric sequence. The output range does not include 'stop'. + */ +export function range(stop: number): number[]; + +/** + * Generates a numeric sequence starting from the given start and stop values. 'step' defaults to 1. The output range does not include 'stop'. + */ +export function range(start: number, stop: number, step?: number): number[]; + +/** + * Randomizes the order of the specified array using the Fisher–Yates shuffle. + */ +export function shuffle(array: T[], lo?: number, hi?: number): T[]; +export function shuffle(array: Int8Array, lo?: number, hi?: number): Int8Array; +export function shuffle(array: Uint8Array, lo?: number, hi?: number): Uint8Array; +export function shuffle(array: Uint8ClampedArray, lo?: number, hi?: number): Uint8ClampedArray; +export function shuffle(array: Int16Array, lo?: number, hi?: number): Int16Array; +export function shuffle(array: Uint16Array, lo?: number, hi?: number): Uint16Array; +export function shuffle(array: Int32Array, lo?: number, hi?: number): Int32Array; +export function shuffle(array: Uint32Array, lo?: number, hi?: number): Uint32Array; +export function shuffle(array: Float32Array, lo?: number, hi?: number): Float32Array; +export function shuffle(array: Float64Array, lo?: number, hi?: number): Float64Array; + +/** + * Generate an array of approximately count + 1 uniformly-spaced, nicely-rounded values between start and stop (inclusive). + * Each value is a power of ten multiplied by 1, 2 or 5. See also d3.tickIncrement, d3.tickStep and linear.ticks. + * + * Ticks are inclusive in the sense that they may include the specified start and stop values if (and only if) they are exact, + * nicely-rounded values consistent with the inferred step. More formally, each returned tick t satisfies start ≤ t and t ≤ stop. + * + * @param start Start value for ticks + * @param stop Stop value for ticks + * @param count count + 1 is the approximate number of ticks to be returned by d3.ticks. + */ +export function ticks(start: number, stop: number, count: number): number[]; + +/** + * Returns the difference between adjacent tick values if the same arguments were passed to d3.ticks: + * a nicely-rounded value that is a power of ten multiplied by 1, 2 or 5. + * + * Like d3.tickStep, except requires that start is always less than or equal to step, and if the tick step for the given start, + * stop and count would be less than one, returns the negative inverse tick step instead. + * + * This method is always guaranteed to return an integer, and is used by d3.ticks to avoid guarantee that the returned tick values + * are represented as precisely as possible in IEEE 754 floating point. + * + * @param start Start value for ticks + * @param stop Stop value for ticks + * @param count count + 1 is the approximate number of ticks to be returned by d3.ticks. + */ +export function tickIncrement(start: number, stop: number, count: number): number; + +/** + * Returns the difference between adjacent tick values if the same arguments were passed to d3.ticks: + * a nicely-rounded value that is a power of ten multiplied by 1, 2 or 5. + * + * Note that due to the limited precision of IEEE 754 floating point, the returned value may not be exact decimals; + * use d3-format to format numbers for human consumption. + * + * @param start Start value for ticks + * @param stop Stop value for ticks + * @param count count + 1 is the approximate number of ticks to be returned by d3.ticks. + */ +export function tickStep(start: number, stop: number, count: number): number; + +/** + * Transpose a matrix provided in Array of Arrays format. + */ +export function transpose(matrix: ArrayLike>): T[][]; + +/** + * Returns an array of arrays, where the ith array contains the ith element from each of the argument arrays. + * The returned array is truncated in length to the shortest array in arrays. If arrays contains only a single array, the returned array + * contains one-element arrays. With no arguments, the returned array is empty. + */ +export function zip(...arrays: Array>): T[][]; + +// -------------------------------------------------------------------------------------- +// Histogram +// -------------------------------------------------------------------------------------- + +export interface Bin extends Array { + x0: Value | undefined; + x1: Value | undefined; +} + +/** + * Type definition for threshold generator which returns the count of recommended thresholds + */ +export type ThresholdCountGenerator = + (values: ArrayLike, min: number, max: number) => number; + +/** + * Type definition for threshold generator which returns an array of recommended numbers thresholds + */ +export type ThresholdNumberArrayGenerator = + (values: ArrayLike, min: number, max: number) => Value[]; + +/** + * Type definition for threshold generator which returns an array of recommended dates thresholds + */ +export type ThresholdDateArrayGenerator = + (values: ArrayLike, min: Date, max: Date) => Value[]; + +/** + * @deprecated Use ThresholdNumberArrayGenerator or ThresholdDateArrayGenerator. + */ +export type ThresholdArrayGenerator = ThresholdNumberArrayGenerator; + +/** + * @deprecated Use `HistogramGeneratorNumber` for `number` values and `HistogramGeneratorDate for `Date` values. + */ +export interface HistogramGenerator { + (data: ArrayLike): Array>; + + value(): (d: Datum, i: number, data: ArrayLike) => Value; + value(valueAccessor: (d: Datum, i: number, data: ArrayLike) => Value): this; + + domain(): (values: ArrayLike) => [Value, Value] | [undefined, undefined]; + domain(domain: [Value, Value]): this; + domain(domainAccessor: (values: ArrayLike) => [Value, Value] | [undefined, undefined]): this; + + /** + * Set the array of values to be used as thresholds in determining the bins. + * + * Any threshold values outside the domain are ignored. The first bin.x0 is always equal to the minimum domain value, + * and the last bin.x1 is always equal to the maximum domain value. + * + * @param thresholds Array of threshold values used for binning. The elements must + * be of the same type as the materialized values of the histogram. + */ + thresholds(thresholds: ArrayLike): this; +} + +export interface HistogramCommon { + (data: ArrayLike): Array>; + + value(): (d: Datum, i: number, data: ArrayLike) => Value; + value(valueAccessor: (d: Datum, i: number, data: ArrayLike) => Value): this; +} + +export interface HistogramGeneratorDate extends HistogramCommon { + domain(): (values: ArrayLike) => [Date, Date]; + domain(domain: [Date, Date]): this; + domain(domainAccessor: (values: ArrayLike) => [Date, Date]): this; + + thresholds(): ThresholdDateArrayGenerator; + /** + * Set the array of values to be used as thresholds in determining the bins. + * + * Any threshold values outside the domain are ignored. The first bin.x0 is always equal to the minimum domain value, + * and the last bin.x1 is always equal to the maximum domain value. + * + * @param thresholds Array of threshold values used for binning. The elements must + * be of the same type as the materialized values of the histogram. + */ + thresholds(thresholds: ArrayLike): this; + /** + * Set a threshold accessor function, which returns the array of values to be used as + * thresholds in determining the bins. + * + * Any threshold values outside the domain are ignored. The first bin.x0 is always equal to the minimum domain value, + * and the last bin.x1 is always equal to the maximum domain value. + * + * @param thresholds A function which accepts as arguments the array of materialized values, and + * optionally the domain minimum and maximum. The function calculates and returns the array of values to be used as + * thresholds in determining the bins. + */ + thresholds(thresholds: ThresholdDateArrayGenerator): this; +} + +export interface HistogramGeneratorNumber extends HistogramCommon { + domain(): (values: ArrayLike) => [number, number] | [undefined, undefined]; + domain(domain: [number, number]): this; + domain(domainAccessor: (values: ArrayLike) => [number, number] | [undefined, undefined]): this; + + thresholds(): ThresholdCountGenerator | ThresholdNumberArrayGenerator; + /** + * Divide the domain uniformly into approximately count bins. IMPORTANT: This threshold + * setting approach only works, when the materialized values are numbers! + * + * Any threshold values outside the domain are ignored. The first bin.x0 is always equal to the minimum domain value, + * and the last bin.x1 is always equal to the maximum domain value. + * + * @param count The desired number of uniform bins. + */ + thresholds(count: number): this; + /** + * Set a threshold accessor function, which returns the desired number of bins. + * Divides the domain uniformly into approximately count bins. IMPORTANT: This threshold + * setting approach only works, when the materialized values are numbers! + * + * Any threshold values outside the domain are ignored. The first bin.x0 is always equal to the minimum domain value, + * and the last bin.x1 is always equal to the maximum domain value. + * + * @param count A function which accepts as arguments the array of materialized values, and + * optionally the domain minimum and maximum. The function calculates and returns the suggested + * number of bins. + */ + thresholds(count: ThresholdCountGenerator): this; + /** + * Set the array of values to be used as thresholds in determining the bins. + * + * Any threshold values outside the domain are ignored. The first bin.x0 is always equal to the minimum domain value, + * and the last bin.x1 is always equal to the maximum domain value. + * + * @param thresholds Array of threshold values used for binning. The elements must + * be of the same type as the materialized values of the histogram. + */ + thresholds(thresholds: ArrayLike): this; + /** + * Set a threshold accessor function, which returns the array of values to be used as + * thresholds in determining the bins. + * + * Any threshold values outside the domain are ignored. The first bin.x0 is always equal to the minimum domain value, + * and the last bin.x1 is always equal to the maximum domain value. + * + * @param thresholds A function which accepts as arguments the array of materialized values, and + * optionally the domain minimum and maximum. The function calculates and returns the array of values to be used as + * thresholds in determining the bins. + */ + thresholds(thresholds: ThresholdNumberArrayGenerator): this; +} + +export function histogram(): HistogramGeneratorNumber; +export function histogram(): HistogramGeneratorNumber; +export function histogram(): HistogramGeneratorDate; + +/** + * @deprecated Do not use Value generic which mixes number and Date types. Use either number or Date + * (in combination with undefined, as applicable) to obtain a type-specific histogram generator. + */ +export function histogram(): HistogramGenerator; + +// -------------------------------------------------------------------------------------- +// Histogram Thresholds +// -------------------------------------------------------------------------------------- + +export function thresholdFreedmanDiaconis(values: ArrayLike, min: number, max: number): number; // of type ThresholdCountGenerator + +export function thresholdScott(values: ArrayLike, min: number, max: number): number; // of type ThresholdCountGenerator + +export function thresholdSturges(values: ArrayLike): number; // of type ThresholdCountGenerator diff --git a/types/d3-array/v1/tsconfig.json b/types/d3-array/v1/tsconfig.json new file mode 100644 index 0000000000..3edd84862c --- /dev/null +++ b/types/d3-array/v1/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6", + "dom" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../../", + "typeRoots": [ + "../../" + ], + "types": [], + "paths": { + "d3-array": [ + "d3-array/v1" + ] + }, + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "d3-array-tests.ts" + ] +} \ No newline at end of file diff --git a/types/d3-array/v1/tslint.json b/types/d3-array/v1/tslint.json new file mode 100644 index 0000000000..54efb0b84e --- /dev/null +++ b/types/d3-array/v1/tslint.json @@ -0,0 +1,7 @@ +{ + "extends": "dtslint/dt.json", + "rules": { + "unified-signatures": false, + "no-unnecessary-generics": false + } +} diff --git a/types/d3/tsconfig.json b/types/d3/tsconfig.json index bc3e8cf886..9a4848b338 100644 --- a/types/d3/tsconfig.json +++ b/types/d3/tsconfig.json @@ -13,6 +13,11 @@ "typeRoots": [ "../" ], + "paths": { + "d3-array": [ + "d3-array/v1" + ] + }, "types": [], "noEmit": true, "forceConsistentCasingInFileNames": true diff --git a/types/d3/v4/tsconfig.json b/types/d3/v4/tsconfig.json index bf267af99d..6b2cee09dd 100644 --- a/types/d3/v4/tsconfig.json +++ b/types/d3/v4/tsconfig.json @@ -19,6 +19,9 @@ ], "d3": [ "d3/v4" + ], + "d3-array": [ + "d3-array/v1" ] }, "types": [], diff --git a/types/d3kit/tsconfig.json b/types/d3kit/tsconfig.json index 40e266f6f9..79051ab233 100644 --- a/types/d3kit/tsconfig.json +++ b/types/d3kit/tsconfig.json @@ -13,6 +13,11 @@ "typeRoots": [ "../" ], + "paths": { + "d3-array": [ + "d3-array/v1" + ] + }, "types": [], "noEmit": true, "forceConsistentCasingInFileNames": true diff --git a/types/react-faux-dom/tsconfig.json b/types/react-faux-dom/tsconfig.json index 198db32576..ed6a386404 100644 --- a/types/react-faux-dom/tsconfig.json +++ b/types/react-faux-dom/tsconfig.json @@ -13,6 +13,11 @@ "typeRoots": [ "../" ], + "paths": { + "d3-array": [ + "d3-array/v1" + ] + }, "types": [], "noEmit": true, "forceConsistentCasingInFileNames": true, diff --git a/types/venn/tsconfig.json b/types/venn/tsconfig.json index 1c2dcb77e6..4981507227 100644 --- a/types/venn/tsconfig.json +++ b/types/venn/tsconfig.json @@ -13,6 +13,11 @@ "typeRoots": [ "../" ], + "paths": { + "d3-array": [ + "d3-array/v1" + ] + }, "types": [], "noEmit": true, "forceConsistentCasingInFileNames": true