Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 90 additions & 78 deletions types/underscore/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ declare module _ {
: TItem
: T;

// if T is an inferrable pair, the value type for the pair
// if T is a list, assume that it contains pairs of some type, so any
// if T isn't a list, there's no way that it can provide pairs, so never
type PairValue<T> =
T extends [EnumerableKey, infer TValue] ? TValue
: T extends List<infer TValue> ? TValue
: never;

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

type Truthy<T> = Exclude<T, AnyFalsy>;
Expand Down Expand Up @@ -813,54 +821,41 @@ declare module _ {
unique: UnderscoreStatic['uniq'];

/**
* Merges together the values of each of the arrays with the values at the corresponding position.
* Useful when you have separate data sources that are coordinated through matching array indexes.
* If you're working with a matrix of nested arrays, zip.apply can transpose the matrix in a similar fashion.
* @param arrays The arrays to merge/zip.
* @return Zipped version of `arrays`.
**/
zip(...arrays: any[][]): any[][];

/**
* @see _.zip
**/
zip(...arrays: any[]): any[];

/**
* The opposite of zip. Given a number of arrays, returns a series of new arrays, the first
* of which contains all of the first elements in the input arrays, the second of which
* contains all of the second elements, and so on. Use with apply to pass in an array
* of arrays
* @param arrays The arrays to unzip.
* @return Unzipped version of `arrays`.
**/
unzip(...arrays: any[][]): any[][];

/**
* Converts arrays into objects. Pass either a single list of [key, value] pairs, or a
* list of keys, and a list of values.
* @param keys Key array.
* @param values Value array.
* @return An object containing the `keys` as properties and `values` as the property values.
**/
object<TResult extends {}>(
keys: _.List<string>,
values: _.List<any>): TResult;
* Merges together the values of each of the `lists` with the values at
* the corresponding position. Useful when you have separate data
* sources that are coordinated through matching list indexes.
* @param lists The lists to zip.
* @returns The zipped version of `lists`.
**/
zip(...lists: List<any>[]): any[][];

/**
* Converts arrays into objects. Pass either a single list of [key, value] pairs, or a
* list of keys, and a list of values.
* @param keyValuePairs Array of [key, value] pairs.
* @return An object containing the `keys` as properties and `values` as the property values.
**/
object<TResult extends {}>(...keyValuePairs: any[][]): TResult;
* The opposite of zip. Given a list of lists, returns a series of new
* arrays, the first of which contains all of the first elements in the
* input lists, the second of which contains all of the second
* elements, and so on.
* @param lists The lists to unzip.
* @returns The unzipped version of `lists`.
**/
unzip(lists: List<List<any>>): any[][];

/**
* @see _.object
**/
object<TResult extends {}>(
list: _.List<any>,
values?: any): TResult;
* Converts lists into objects. Pass either a single `list` of
* [key, value] pairs, or a `list` of keys and a list of `values`.
* Passing by pairs is the reverse of pairs. If duplicate keys exist,
* the last value wins.
* @param list A list of [key, value] pairs or a list of keys.
* @param values If `list` is a list of keys, a list of values
* corresponding to those keys.
* @retursn An object comprised of the provided keys and values.
**/
object<TList extends List<EnumerableKey>, TValue>(
list: TList,
values: List<TValue>
): Dictionary<TValue | undefined>;
object<TList extends List<List<any>>>(
list: TList
): Dictionary<PairValue<TypeOfList<TList>>>;

/**
* Returns the index at which value can be found in the array, or -1 if value is not present in the array.
Expand Down Expand Up @@ -4439,27 +4434,34 @@ declare module _ {
unique: Underscore<T, V>['uniq'];

/**
* Wrapped type `any[][]`.
* @see _.zip
**/
zip(...arrays: any[][]): any[][];

/**
* Wrapped type `any[][]`.
* @see _.unzip
**/
unzip(...arrays: any[][]): any[][];
* Merges together the values of each of the `lists` (including the
* wrapped list) with the values at the corresponding position. Useful
* when you have separate data sources that are coordinated through
* matching list indexes.
* @returns The zipped version of the wrapped list and `lists`.
**/
zip(...lists: List<any>[]): any[][];

/**
* Wrapped type `any[][]`.
* @see _.object
**/
object(...keyValuePairs: any[][]): any;
* The opposite of zip. Given the wrapped list of lists, returns a
* series of new arrays, the first of which contains all of the first
* elements in the wrapped lists, the second of which contains all of
* the second elements, and so on.
* @returns The unzipped version of the wrapped lists.
**/
unzip(): any[][];

/**
* @see _.object
**/
object(values?: any): any;
* Converts lists into objects. Call on either a wrapped list of
* [key, value] pairs, or a wrapped list of keys and a list of
* `values`. Passing by pairs is the reverse of pairs. If duplicate
* keys exist, the last value wins.
* @param values If the wrapped list is a list of keys, a list of
* values corresponding to those keys.
* @returns An object comprised of the provided keys and values.
**/
object<TValue>(values: List<TValue>): Dictionary<TValue | undefined>;
object(): Dictionary<PairValue<T>>;

/**
* Wrapped type `any[]`.
Expand Down Expand Up @@ -5459,27 +5461,37 @@ declare module _ {
unique: _Chain<T, V>['uniq'];

/**
* Wrapped type `any[][]`.
* @see _.zip
**/
zip(...arrays: any[][]): _Chain<T>;

/**
* Wrapped type `any[][]`.
* @see _.unzip
**/
unzip(...arrays: any[][]): _Chain<T>;
* Merges together the values of each of the `lists` (including the
* wrapped list) with the values at the corresponding position. Useful
* when you have separate data sources that are coordinated through
* matching list indexes.
* @returns A chain wrapper around the zipped version of the wrapped
* list and `lists`.
**/
zip(...arrays: List<any>[]): _Chain<any[], any[][]>;

/**
* Wrapped type `any[][]`.
* @see _.object
**/
object(...keyValuePairs: any[][]): _Chain<T>;
* The opposite of zip. Given the wrapped list of lists, returns a
* series of new arrays, the first of which contains all of the first
* elements in the wrapped lists, the second of which contains all of
* the second elements, and so on.
* @returns A chain wrapper aoround the unzipped version of the wrapped
* lists.
**/
unzip(): _Chain<any[], any[][]>;

/**
* @see _.object
**/
object(values?: any): _Chain<T>;
* Converts lists into objects. Call on either a wrapped list of
* [key, value] pairs, or a wrapped list of keys and a list of
* `values`. Passing by pairs is the reverse of pairs. If duplicate
* keys exist, the last value wins.
* @param values If the wrapped list is a list of keys, a list of
* values corresponding to those keys.
* @returns A chain wrapper around an object comprised of the provided
* keys and values.
**/
object<TValue>(values: List<TValue>): _Chain<TValue | undefined, Dictionary<TValue | undefined>>;
object(): _Chain<PairValue<T>, Dictionary<PairValue<T>>>;

/**
* Wrapped type `any[]`.
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 @@ -656,6 +656,7 @@ declare const resultUnionStringListMemoIterator: (prev: string | number, value:
declare const anyCollectionVoidIterator: (element: any, index: string | number, collection: any) => void;

const simpleNumber = 7;
declare const simpleNumberList: _.List<number>;
declare const simpleNumberDictionary: _.Dictionary<number>;

declare const simpleBooleanList: _.List<boolean>;
Expand All @@ -671,6 +672,9 @@ type Truthies = string | number | boolean | object | Function | StringRecord | (
declare const truthyFalsyList: _.List<Truthies | _.AnyFalsy>;
declare const maybeTruthyFalsyList: _.List<Truthies | _.AnyFalsy> | null | undefined;

declare const level2UnionList: _.List<_.List<string | number>>;
declare const tupleList: _.List<[string, number]>;

// 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 @@ -2219,6 +2223,55 @@ undefinedIdentityIterateeResult; // $ExpectType StringRecord
extractChainTypes(_.chain(stringRecordList).unique(true, stringRecordPropertyPath)); // $ExpectType ChainType<StringRecord[], StringRecord>
}

// zip
{
// multiple arguments
_.zip(simpleStringList, simpleNumberList, stringRecordList); // $ExpectType any[][]
_(simpleStringList).zip(simpleNumberList, stringRecordList); // $ExpectType any[][]
extractChainTypes(_.chain(simpleStringList).zip(simpleNumberList, stringRecordList)); // $ExpectType ChainType<any[][], any[]>

// single arguments
_.zip(simpleStringList); // $ExpectType any[][]
_(simpleStringList).zip(); // $ExpectType any[][]
extractChainTypes(_.chain(simpleStringList).zip()); // $ExpectType ChainType<any[][], any[]>
}

// unzip
{
// tuple lists
_.unzip(tupleList); // $ExpectType any[][]
_(tupleList).unzip(); // $ExpectType any[][]
extractChainTypes(_.chain(tupleList).unzip()); // $ExpectType ChainType<any[][], any[]>

// nested lists
_.unzip(level2UnionList); // $ExpectType any[][]
_(level2UnionList).unzip(); // $ExpectType any[][]
extractChainTypes(_.chain(level2UnionList).unzip()); // $ExpectType ChainType<any[][], any[]>
}

// object
{
// key and value lists
_.object(simpleStringList, simpleNumberList); // $ExpectType Dictionary<number | undefined>
_(simpleStringList).object(simpleNumberList); // $ExpectType Dictionary<number | undefined>
extractChainTypes(_.chain(simpleStringList).object(simpleNumberList)); // $ExpectType ChainType<Dictionary<number | undefined>, number | undefined>

// tuple lists
_.object(tupleList); // $ExpectType Dictionary<number>
_(tupleList).object(); // $ExpectType Dictionary<number>
extractChainTypes(_.chain(tupleList).object()); // $ExpectType ChainType<Dictionary<number>, number>

// nested lists
_.object(level2UnionList); // $ExpectType Dictionary<string | number>
_(level2UnionList).object(); // $ExpectType Dictionary<string | number>
extractChainTypes(_.chain(level2UnionList).object()); // $ExpectType ChainType<Dictionary<string | number>, string | number>

// non-nested lists
_.object(stringRecordList); // $ExpectError
_(stringRecordList).object(); // $ExpectType Dictionary<never>
extractChainTypes(_.chain(stringRecordList).object()); // $ExpectType ChainType<Dictionary<never>, never>
}

// chunk
{
const length = 2;
Expand Down