diff --git a/d3-array/d3-array-tests.ts b/d3-array/d3-array-tests.ts index 26ef2d3ef5..e086fd2502 100644 --- a/d3-array/d3-array-tests.ts +++ b/d3-array/d3-array-tests.ts @@ -25,7 +25,6 @@ class NumCoercible { } } - class MixedObject { public num: number; @@ -40,18 +39,23 @@ class MixedObject { this.date = date; } } + let num: number; -let str: string; -let numeric: NumCoercible; let date: Date; -let extentNum: [number, number]; -let extentStr: [string, string]; -let extentNumeric: [NumCoercible, NumCoercible]; -let extentDateMixed: [d3Array.Primitive, d3Array.Primitive]; -let extentMixed: [d3Array.Primitive | NumCoercible, d3Array.Primitive | NumCoercible]; -let extentDate: [Date, Date]; + +let numOrUndefined: number | undefined; +let strOrUndefined: string | undefined; +let numericOrUndefined: NumCoercible | undefined; +let dateOrUndefined: Date | 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]; +let numbersOrUndefinedArray = [10, 20, undefined, null, 40, 50]; let stringyNumbersArray = ['10', '20', '30', '40', '50']; let 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)]; @@ -62,7 +66,31 @@ let mixedObjectArray = [ new MixedObject(40, new Date(2014, 3, 15)), new MixedObject(50, new Date(2017, 4, 15)) ]; +let mixedObjectOrUndefinedArray = [...mixedObjectArray, undefined] +function accessorMixedObjectToNum(datum: MixedObject, index: number, array: Array): number { + return datum.num; +} + +function accessorMixedObjectToStr(datum: MixedObject, index: number, array: Array): string { + return datum.str; +} + +function accessorMixedObjectToNumeric(datum: MixedObject, index: number, array: Array): NumCoercible { + return datum.numeric; +} + +function accessorMixedObjectToDate(datum: MixedObject, index: number, array: Array): Date { + return datum.date; +} + +function accessorMixedObjectToNumOrUndefined(datum: MixedObject | undefined, index: number, array: Array): number | undefined | null { + return datum ? datum.num : undefined; +} + +function accessorMixedObjectToStrOrUndefined(datum: MixedObject | undefined, index: number, array: Array): string | undefined | null { + return datum ? datum.str : undefined; +} // ----------------------------------------------------------------------------- // Test Statistics @@ -72,186 +100,109 @@ let mixedObjectArray = [ // without accessors -num = d3Array.max(numbersArray); -str = d3Array.max(stringyNumbersArray); -numeric = d3Array.max(numericArray); -date = d3Array.max(dateArray); +numOrUndefined = d3Array.max(numbersArray); +strOrUndefined = d3Array.max(stringyNumbersArray); +numericOrUndefined = d3Array.max(numericArray); +dateOrUndefined = d3Array.max(dateArray); // with accessors -num = d3Array.max(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.num; -}); - -str = d3Array.max(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.str; -}); - -numeric = d3Array.max(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.numeric; -}); - -date = d3Array.max(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.date; -}); +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); // min() ----------------------------------------------------------------------- // without accessors -num = d3Array.min(numbersArray); -str = d3Array.min(stringyNumbersArray); -numeric = d3Array.min(numericArray); -date = d3Array.min(dateArray); +numOrUndefined = d3Array.min(numbersArray); +strOrUndefined = d3Array.min(stringyNumbersArray); +numericOrUndefined = d3Array.min(numericArray); +dateOrUndefined = d3Array.min(dateArray); // with accessors -num = d3Array.min(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.num; -}); - -str = d3Array.min(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.str; -}); - -numeric = d3Array.min(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.numeric; -}); - -date = d3Array.min(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.date; -}); +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); // extent() -------------------------------------------------------------------- // without accessors -extentNum = d3Array.extent(numbersArray); -extentStr = d3Array.extent(stringyNumbersArray); -extentNumeric = d3Array.extent(numericArray); -extentDate = d3Array.extent(dateArray); -extentMixed = d3Array.extent([new NumCoercible(10), 13, '12', true]); +numOrUndefinedExtent = d3Array.extent(numbersArray); +strOrUndefinedExtent = d3Array.extent(stringyNumbersArray); +numericOrUndefinedExtent = d3Array.extent(numericArray); +dateOrUndefinedExtent = d3Array.extent(dateArray); // with accessors -extentNum = d3Array.extent(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.num; -}); - -extentStr = d3Array.extent(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.str; -}); - -extentMixed = d3Array.extent(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.numeric; -}); - -extentDateMixed = d3Array.extent(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.date; -}); +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); // mean() ---------------------------------------------------------------------- -num = d3Array.mean(numbersArray); +numOrUndefined = d3Array.mean(numbersArray); +numOrUndefined = d3Array.mean(numericArray); +numOrUndefined = d3Array.mean(numbersOrUndefinedArray); -num = d3Array.mean(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.num; -}); +numOrUndefined = d3Array.mean(mixedObjectArray, accessorMixedObjectToNum); +numOrUndefined = d3Array.mean(mixedObjectOrUndefinedArray, accessorMixedObjectToNumOrUndefined); // median() -------------------------------------------------------------------- -num = d3Array.median(numbersArray); +numOrUndefined = d3Array.median(numbersArray); +numOrUndefined = d3Array.median(numericArray); +numOrUndefined = d3Array.median(numbersOrUndefinedArray); -num = d3Array.median(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.num; -}); +numOrUndefined = d3Array.median(mixedObjectArray, accessorMixedObjectToNum); +numOrUndefined = d3Array.median(mixedObjectOrUndefinedArray, accessorMixedObjectToNumOrUndefined); // quantile() ------------------------------------------------------------------ -num = d3Array.quantile(numbersArray, 0.5); +numOrUndefined = d3Array.quantile(numbersArray, 0.5); +numOrUndefined = d3Array.quantile(numericArray, 0.5); +numOrUndefined = d3Array.quantile(numbersOrUndefinedArray, 0.5); -num = d3Array.quantile(mixedObjectArray, 0.5, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.num; -}); +numOrUndefined = d3Array.quantile(mixedObjectArray, 0.5, accessorMixedObjectToNum); +numOrUndefined = d3Array.quantile(mixedObjectOrUndefinedArray, 0.5, accessorMixedObjectToNumOrUndefined); // sum() ----------------------------------------------------------------------- +numOrUndefined = d3Array.sum(numbersArray); +numOrUndefined = d3Array.sum(numericArray); +numOrUndefined = d3Array.sum(numbersOrUndefinedArray); -num = d3Array.sum(numbersArray); - -num = d3Array.sum(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.num; -}); +numOrUndefined = d3Array.sum(mixedObjectArray, accessorMixedObjectToNum); +numOrUndefined = d3Array.sum(mixedObjectOrUndefinedArray, accessorMixedObjectToNumOrUndefined); // deviation() ----------------------------------------------------------------- -num = d3Array.deviation(numbersArray); +numOrUndefined = d3Array.deviation(numbersArray); +numOrUndefined = d3Array.deviation(numericArray); +numOrUndefined = d3Array.deviation(numbersOrUndefinedArray); -num = d3Array.deviation(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.num; -}); +numOrUndefined = d3Array.deviation(mixedObjectArray, accessorMixedObjectToNum); +numOrUndefined = d3Array.deviation(mixedObjectOrUndefinedArray, accessorMixedObjectToNumOrUndefined); // variance() ------------------------------------------------------------------ -num = d3Array.variance(numbersArray); +numOrUndefined = d3Array.variance(numbersArray); +numOrUndefined = d3Array.variance(numericArray); +numOrUndefined = d3Array.variance(numbersOrUndefinedArray); -num = d3Array.variance(mixedObjectArray, function (datum, index, array) { - let d: MixedObject = datum; - let i: number = index; - let arr: Array = array; - return datum.num; -}); +numOrUndefined = d3Array.variance(mixedObjectArray, accessorMixedObjectToNum); +numOrUndefined = d3Array.variance(mixedObjectOrUndefinedArray, accessorMixedObjectToNumOrUndefined); // ----------------------------------------------------------------------------- // Test Searching Arrays @@ -259,8 +210,18 @@ num = d3Array.variance(mixedObjectArray, function (datum, index, array) { // scan() ---------------------------------------------------------------------- -num = d3Array.scan(mixedObjectArray, function (a, b) { - return a.num - b.num; // a and b are of type MixedObject +numOrUndefined = d3Array.scan(numbersArray) + +numOrUndefined = d3Array.scan(mixedObjectArray, function (a, b) { + let aElem: MixedObject = a; + let bElem: MixedObject = b; + return a.num - b.num; +}); + +numOrUndefined = d3Array.scan(mixedObjectOrUndefinedArray, function (a, b) { + let aElem: MixedObject | undefined = a; + let bElem: MixedObject | undefined = b; + return a && b ? a.num - b.num : NaN; }); // bisectLeft() ---------------------------------------------------------------- @@ -334,12 +295,14 @@ num = mixedObjectDateBisectorObject.right(mixedObjectArray, new Date(2015, 3, 14 // 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)); @@ -364,12 +327,11 @@ let testArrays: MixedObject[][] = [ ] ]; - let mergedArray: MixedObject[]; mergedArray = d3Array.merge(testArrays); // inferred type mergedArray = d3Array.merge(testArrays); // explicit type -// mergedArray = d3.merge([[10, 40, 30], [15, 30]]); // fails, type mismatch +// mergedArray = d3Array.merge([[10, 40, 30], [15, 30]]); // fails, type mismatch // pairs() --------------------------------------------------------------------- diff --git a/d3-array/index.d.ts b/d3-array/index.d.ts index e3bd2d549d..336eb2bc83 100644 --- a/d3-array/index.d.ts +++ b/d3-array/index.d.ts @@ -1,8 +1,10 @@ -// Type definitions for D3JS d3-array module v1.0.1 +// Type definitions for D3JS d3-array module 1.0 // Project: https://github.com/d3/d3-array // Definitions by: Alex Ford , Boris Yankov , Tom Wanzek // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// Last module patch version validated against: 1.0.2 + // -------------------------------------------------------------------------- // Shared Types and Interfaces // -------------------------------------------------------------------------- @@ -20,17 +22,11 @@ interface Numeric { valueOf(): number; } - // -------------------------------------------------------------------------------------- // Descriptive Statistics // -------------------------------------------------------------------------------------- -/** - * Return the maximum value in the array of numbers using natural order. - */ -export function max(array: number[]): number | undefined; - /** * Return the maximum value in the array of strings using natural order. */ @@ -41,25 +37,15 @@ export function max(array: string[]): string | undefined; */ export function max(array: T[]): T | undefined; -/** - * Return the maximum value in the array using natural order and a projection function to map values to numbers. - */ -export function max(array: T[], accessor: (datum: T, index: number, array: T[]) => number): number | undefined; - /** * Return the maximum value in the array using natural order and a projection function to map values to strings. */ -export function max(array: T[], accessor: (datum: T, index: number, array: T[]) => string): string | undefined; +export function max(array: T[], accessor: (datum: T, index: number, array: T[]) => 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: T[], accessor: (datum: T, index: number, array: T[]) => U): U | undefined; - -/** - * Return the minimum value in the array using natural order. - */ -export function min(array: number[]): number | undefined; +export function max(array: T[], accessor: (datum: T, index: number, array: T[]) => U | undefined | null): U | undefined; /** * Return the minimum value in the array using natural order. @@ -74,25 +60,15 @@ export function min(array: T[]): T | undefined; /** * Return the minimum value in the array using natural order. */ -export function min(array: T[], accessor: (datum: T, index: number, array: T[]) => number): number | undefined; +export function min(array: T[], accessor: (datum: T, index: number, array: T[]) => string | undefined | null): string | undefined; /** * Return the minimum value in the array using natural order. */ -export function min(array: T[], accessor: (datum: T, index: number, array: T[]) => string): string | undefined; - -/** - * Return the minimum value in the array using natural order. - */ -export function min(array: T[], accessor: (datum: T, index: number, array: T[]) => U): U | undefined; +export function min(array: T[], accessor: (datum: T, index: number, array: T[]) => U | undefined | null): U | undefined; -/** - * Return the min and max simultaneously. - */ -export function extent(array: number[]): [number, number] | [undefined, undefined]; - /** * Return the min and max simultaneously. */ @@ -106,79 +82,70 @@ export function extent(array: T[]): [T, T] | [undefined, unde /** * Return the min and max simultaneously. */ -export function extent(array: Array): [T | Primitive, T | Primitive] | [undefined, undefined]; +export function extent(array: T[], accessor: (datum: T, index: number, array: T[]) => string | undefined | null): [string, string] | [undefined, undefined]; /** * Return the min and max simultaneously. */ -export function extent(array: T[], accessor: (datum: T, index: number, array: T[]) => number): [number, number] | [undefined, undefined]; - -/** - * Return the min and max simultaneously. - */ -export function extent(array: T[], accessor: (datum: T, index: number, array: T[]) => string): [string, string] | [undefined, undefined]; - -/** - * Return the min and max simultaneously. - */ -export function extent(array: T[], accessor: (datum: T, index: number, array: T[]) => U): [U, U ] | [undefined, undefined]; +export function extent(array: T[], accessor: (datum: T, index: number, array: T[]) => U | undefined | null): [U, U] | [undefined, undefined]; /** * Return the mean of an array of numbers */ -export function mean(array: number[]): number | undefined; -export function mean(array: T[], accessor: (datum: T, index: number, array: T[]) => number): number | undefined; +export function mean(array: Array): number | undefined; +export function mean(array: T[], accessor: (datum: T, index: number, array: T[]) => number | undefined | null): number | undefined; /** * Return the median of an array of numbers */ -export function median(array: number[]): number | undefined; -export function median(array: T[], accessor: (element: T, i: number, array: T[]) => number): number | undefined; +export function median(array: Array): number | undefined; +export function median(array: T[], accessor: (element: T, i: number, array: T[]) => number | undefined | null): number | undefined; /** * Returns the p-quantile of an array of numbers */ -export function quantile(array: number[], p: number): number | undefined; -export function quantile(array: T[], p: number, accessor: (element: T, i: number, array: T[]) => number): number | undefined; +export function quantile(array: Array, p: number): number | undefined; +export function quantile(array: T[], p: number, accessor: (element: T, i: number, array: T[]) => number | undefined | null): number | undefined; /** * Compute the sum of an array of numbers. */ -export function sum(array: number[]): number; +export function sum(array: Array): number; /** * Compute the sum of an array, using the given accessor to convert values to numbers. */ -export function sum(array: T[], accessor: (datum: T, index: number, array: T[]) => number): number; +export function sum(array: T[], accessor: (datum: T, index: number, array: T[]) => 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: number[]): number | undefined; +export function deviation(array: Array): 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: T[], accessor: (datum: T, index: number, array: T[]) => number): number | undefined; +export function deviation(array: T[], accessor: (datum: T, index: number, array: T[]) => number | undefined | null): number | undefined; /** * Compute an unbiased estimator of the population variance of the given array of numbers. */ -export function variance(array: number[]): number | undefined; +export function variance(array: Array): 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: T[], accessor: (datum: T, index: number, array: T[]) => number): number | undefined; +export function variance(array: T[], accessor: (datum: T, index: number, array: T[]) => number | undefined | null): number | undefined; // -------------------------------------------------------------------------------------- // Searching Arrays // -------------------------------------------------------------------------------------- -export function scan(array: T[], comparator: (a: T, b: T) => number): number; +export function scan(array: number[], comparator?: (a: number, b: number) => number): number | undefined; +export function scan(array: T[], comparator: (a: T, b: T) => number): number | undefined; export function bisectLeft(array: number[], x: number, lo?: number, hi?: number): number; export function bisectLeft(array: string[], x: string, lo?: number, hi?: number): number; @@ -202,16 +169,16 @@ export function bisector(accessor: (x: T) => U): Bisector; /** * Compares two primitive values for sorting (in ascending order). */ -export function ascending(a: Primitive, b: Primitive): number; +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, b: Primitive): number; +export function descending(a: Primitive | undefined, b: Primitive | undefined): number; // -------------------------------------------------------------------------------------- -// Transforming Arrays +// Transforming Arrays // -------------------------------------------------------------------------------------- @@ -236,7 +203,6 @@ export function permute(array: { [key: number]: T }, keys: number[]): T[]; */ export function permute(object: { [key: string]: T }, keys: string[]): T[]; - /** * Generates a 0-based numeric sequence. The output range does not include 'stop'. */ diff --git a/d3-array/tsconfig.json b/d3-array/tsconfig.json index db900a4087..b70f6aed80 100644 --- a/d3-array/tsconfig.json +++ b/d3-array/tsconfig.json @@ -7,7 +7,7 @@ ], "noImplicitAny": true, "noImplicitThis": true, - "strictNullChecks": false, + "strictNullChecks": true, "baseUrl": "../", "typeRoots": [ "../" diff --git a/d3-array/tslint.json b/d3-array/tslint.json new file mode 100644 index 0000000000..68d10d72a6 --- /dev/null +++ b/d3-array/tslint.json @@ -0,0 +1,6 @@ +{ + "extends": "../tslint.json", + "rules": { + "unified-signatures": false + } +}