Skip to content
Merged
131 changes: 77 additions & 54 deletions types/underscore/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ declare module _ {
: TItem
: T;

type AnyFalsy = undefined | null | false | '' | 0;

type Truthy<T> = Exclude<T, AnyFalsy>;

type _ChainSingle<V> = _Chain<TypeOfCollection<V>, V>;

interface Cancelable {
Expand Down Expand Up @@ -781,12 +785,13 @@ declare module _ {
drop: UnderscoreStatic['rest'];

/**
* Returns a copy of the array with all falsy values removed. In JavaScript, false, null, 0, "",
* undefined and NaN are all falsy.
* @param array Array to compact.
* @return Copy of `array` without false values.
**/
compact<T>(array: _.List<T | null | undefined | false | "" | 0> | null | undefined): T[]
* Returns a copy of `list` with all falsy values removed. In
* JavaScript, false, null, 0, "", undefined and NaN are all falsy.
* @param list The list to compact.
* @returns An array containing the elements of `list` without falsy
* values.
**/
compact<V extends List<any> | null | undefined>(list: V): Truthy<TypeOfList<V>>[];

/**
* Flattens a nested array (the nesting can be to any depth). If you pass shallow, the array will
Expand Down Expand Up @@ -998,27 +1003,29 @@ declare module _ {
): number;

/**
* A function to create flexibly-numbered lists of integers, handy for each and map loops. start, if omitted,
* defaults to 0; step defaults to 1. Returns a list of integers from start to stop, incremented (or decremented)
* by step, exclusive.
* @param start Start here.
* @param stop Stop here.
* @param step The number to count up by each iteration, optional, default = 1.
* @return Array of numbers from `start` to `stop` with increments of `step`.
**/

* A function to create flexibly-numbered lists of integers, handy for
* `each` and `map` loops. Returns a list of integers from
* `startOrStop` (inclusive) to `stop` (exclusive), incremented
* (or decremented) by `step`. Note that ranges that `stop` before they
* `start` are considered to be zero-length instead of negative - if
* you'd like a negative range, use a negative `step`.
*
* If `stop` is not specified, `startOrStop` will be the number to stop
* at and the default start of 0 will be used.
* @param startOrStop If `stop` is specified, the number to start at.
* Otherwise, this is the number to stop at and the default start of 0
* will be used.
* @param stop The number to stop at.
* @param step The number to count up by each iteration, optional,
* default = 1.
* @returns An array of numbers from start to `stop` with increments
* of `step`.
**/
range(
start: number,
stop: number,
step?: number): number[];

/**
* @see _.range
* @param stop Stop here.
* @return Array of numbers from 0 to `stop` with increments of 1.
* @note If start is not specified the implementation will never pull the step (step = arguments[2] || 0)
**/
range(stop: number): number[];
startOrStop: number,
stop?: number,
step?: number
): number[];

/**
* Chunks a list into multiple arrays, each containing length or fewer items.
Expand Down Expand Up @@ -4414,10 +4421,12 @@ declare module _ {
drop: Underscore<T, V>['rest'];

/**
* Wrapped type `any[]`.
* @see _.compact
**/
compact(): T[];
* Returns a copy of the wrapped list with all falsy values removed. In
* JavaScript, false, null, 0, "", undefined and NaN are all falsy.
* @returns An array containing the elements of the wrapped list without
* falsy values.
**/
compact(): Truthy<T>[];

/**
* Flattens the wrapped nested list (the nesting can be to any depth). If you pass shallow, the list will
Expand Down Expand Up @@ -4544,16 +4553,22 @@ declare module _ {
sortedIndex(value: T, iteratee?: Iteratee<V, any>, context?: any): number;

/**
* Wrapped type `number`.
* @see _.range
**/
range(stop: number, step?: number): number[];

/**
* Wrapped type `number`.
* @see _.range
**/
range(): number[];
* A function to create flexibly-numbered lists of integers, handy for
* `each` and `map` loops. Returns a list of integers from
* the wrapped value (inclusive) to `stop` (exclusive), incremented
* (or decremented) by `step`. Note that ranges that `stop` before they
* `start` are considered to be zero-length instead of negative - if
* you'd like a negative range, use a negative `step`.
*
* If `stop` is not specified, the wrapped value will be the number to
* stop at and the default start of 0 will be used.
* @param stop The number to stop at.
* @param step The number to count up by each iteration, optional,
* default = 1.
* @returns An array of numbers from start to `stop` with increments
* of `step`.
**/
range(stop?: number, step?: number): number[];

/**
* Chunks a wrapped list into multiple arrays, each containing length or fewer items.
Expand Down Expand Up @@ -5411,10 +5426,12 @@ declare module _ {
drop: _Chain<T, V>['rest'];

/**
* Wrapped type `any[]`.
* @see _.compact
**/
compact(): _Chain<T>;
* Returns a copy of the wrapped list with all falsy values removed. In
* JavaScript, false, null, 0, "", undefined and NaN are all falsy.
* @returns A chain wrapper around an array containing the elements of
* the wrapped list without falsy values.
**/
compact(): _Chain<Truthy<T>, Truthy<T>[]>;

/**
* Flattens the wrapped nested list (the nesting can be to any depth). If you pass shallow, the list will
Expand Down Expand Up @@ -5542,16 +5559,22 @@ declare module _ {
sortedIndex(value: T, iteratee?: _ChainIteratee<V, any, T>, context?: any): _ChainSingle<number>;

/**
* Wrapped type `number`.
* @see _.range
**/
range(stop: number, step?: number): _Chain<T>;

/**
* Wrapped type `number`.
* @see _.range
**/
range(): _Chain<T>;
* A function to create flexibly-numbered lists of integers, handy for
* `each` and `map` loops. Returns a list of integers from
* the wrapped value (inclusive) to `stop` (exclusive), incremented
* (or decremented) by `step`. Note that ranges that `stop` before they
* `start` are considered to be zero-length instead of negative - if
* you'd like a negative range, use a negative `step`.
*
* If `stop` is not specified, the wrapped value will be the number to
* stop at and the default start of 0 will be used.
* @param stop The number to stop at.
* @param step The number to count up by each iteration, optional,
* default = 1.
* @returns A chain wrapper around an array of numbers from start to
* `stop` with increments of `step`.
**/
range(stop?: number, step?: number): _Chain<number, number[]>;

/**
* Chunks a wrapped list into multiple arrays, each containing length or fewer items.
Expand Down
53 changes: 53 additions & 0 deletions types/underscore/underscore-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,19 @@ _.chain([
.sample()
.value();

// $ExpectType number[]
_.chain([1, 2, 3, 4, 5, 6])
.sample()
.range(10)
.value();

// $ExpectType [number[], number[]]
_.chain([[1, 2, 3], [4, undefined, 5], [undefined, undefined, 6]])
.flatten()
.compact()
.partition(n => n > 3)
.value();

// verify that partial objects can be provided without error to where and findWhere for a union type collection
// where no types in the union share the same property names
declare const nonIntersectinglTypeUnion: _.Dictionary<{ one: string; } | { two: number; }>;
Expand Down Expand Up @@ -645,6 +658,10 @@ declare const maybeFunction: (() => void) | undefined;
declare const maybeStringArray: string[] | undefined;
declare const stringy: StringRecord | string;

type Truthies = string | number | boolean | object | Function | StringRecord | (() => void);
declare const truthyFalsyList: _.List<Truthies | _.AnyFalsy>;
declare const maybeTruthyFalsyList: _.List<Truthies | _.AnyFalsy> | null | undefined;

// avoid referencing types under test directly by translating them to other types to avoid needing to make lots of changes if
// the types under test need to be refactored
interface UnderscoreType<TWrappedValue, TItemType> { }
Expand Down Expand Up @@ -1726,6 +1743,19 @@ undefinedIdentityIterateeResult; // $ExpectType StringRecord
extractChainTypes(_.chain(stringRecordList).drop(simpleNumber)); // $ExpectType ChainType<StringRecord[], StringRecord>
}

// compact
{
// lists
_.compact(truthyFalsyList); // $ExpectType (string | number | true | object | Function | StringRecord | (() => void))[]
_(truthyFalsyList).compact(); // $ExpectType (string | number | true | object | Function | StringRecord | (() => void))[]
extractChainTypes(_.chain(truthyFalsyList).compact()); // $ExpectType ChainType<(string | number | true | object | Function | StringRecord | (() => void))[], string | number | true | object | Function | StringRecord | (() => void)>

// maybe lists
_.compact(maybeTruthyFalsyList); // $ExpectType (string | number | true | object | Function | StringRecord | (() => void))[]
_(maybeTruthyFalsyList).compact(); // $ExpectType (string | number | true | object | Function | StringRecord | (() => void))[]
extractChainTypes(_.chain(maybeTruthyFalsyList).compact()); // $ExpectType ChainType<(string | number | true | object | Function | StringRecord | (() => void))[], string | number | true | object | Function | StringRecord | (() => void)>
}

// flatten
{
// one dimension, deep
Expand Down Expand Up @@ -1985,6 +2015,29 @@ undefinedIdentityIterateeResult; // $ExpectType StringRecord
_.chain([{a: 'a'}, {a: 'b'}]).findLastIndex({ a: 'b' }).value(); // $ExpectType number
}

// range
{
// only stop
_.range(simpleNumber); // $ExpectType number[]
_(simpleNumber).range(); // $ExpectType number[]
extractChainTypes(_.chain(simpleNumber).range()); // $ExpectType ChainType<number[], number>

// start and stop
_.range(simpleNumber, simpleNumber); // $ExpectType number[]
_(simpleNumber).range(simpleNumber); // $ExpectType number[]
extractChainTypes(_.chain(simpleNumber).range(simpleNumber)); // $ExpectType ChainType<number[], number>

// stop and step
_.range(simpleNumber, undefined, simpleNumber); // $ExpectType number[]
_(simpleNumber).range(undefined, simpleNumber); // $ExpectType number[]
extractChainTypes(_.chain(simpleNumber).range(undefined, simpleNumber)); // $ExpectType ChainType<number[], number>

// start, stop, and step
_.range(simpleNumber, simpleNumber, simpleNumber); // $ExpectType number[]
_(simpleNumber).range(simpleNumber, simpleNumber); // $ExpectType number[]
extractChainTypes(_.chain(simpleNumber).range(simpleNumber, simpleNumber)); // $ExpectType ChainType<number[], number>
}

// Objects

// isEqual
Expand Down