Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6402c69
Updating both underscore and chain to have three overloads - one for …
mness-cc Jun 5, 2020
4e0e575
Updating Underscore.value to return the wrapped value type instead of…
mness-cc Jun 5, 2020
b559905
Updating _Chain.chain to continue chaining the wrapped value type.
mness-cc Jun 5, 2020
5daf47b
Removing the _ChainSingle interface in favor of always using _Chain s…
mness-cc Jun 5, 2020
4335411
Adding tests for OOP Style and Chaining.
mness-cc Jun 5, 2020
2159f89
Adding myself to the set of Underscore type definition authors.
mness-cc Jun 5, 2020
6014702
Adding a newline back to the end of the tests file.
mness-cc Jun 5, 2020
f1ab657
Moving the minimum supported TS version to 3.0 so unknown can be used…
mness-cc Jun 5, 2020
70f6bf3
Making some updates to summary comments.
mness-cc Jun 5, 2020
78a3270
Removing extra lines in tests.
mness-cc Jun 5, 2020
a32ea9b
Updating chunk.
mness-cc Jun 5, 2020
21c1724
Adding tests for chunk.
mness-cc Jun 5, 2020
934b3e6
Changing the minimum TS version back to 2.8 since I probably won't ne…
mness-cc Jun 9, 2020
5071964
Reordering tests so new ones are appended to the file rather than pre…
mness-cc Jun 9, 2020
a3e0501
Adding a newline to the end of underscore-tests.ts.
mness-cc Jun 9, 2020
a7903e8
Removing tests that explicitly specify generics and moving $ExpectTyp…
mness-cc Jun 12, 2020
ef26362
Adding tests for more specific list and dictionary types, switching t…
mness-cc Jun 16, 2020
83a553f
Fixing incorrect JSDoc terminators for chunk functions.
mness-cc Jun 18, 2020
93fcb9c
Adding the example from #7931 as a test to verify that it works when …
mness-cc Jun 18, 2020
c0d7c8c
Revert "Removing the _ChainSingle interface in favor of always using …
mness-cc Jun 18, 2020
8f291ae
Updating the Collection type to be more accurate and useful.
mness-cc Jun 18, 2020
f21a05c
Updating _ChainSingle to be an alias to _Chain<TypeOfCollection<V>, V>.
mness-cc Jun 18, 2020
735461e
Also updating the Underscore and chain functions to use never for ite…
reubenrybnik Jun 18, 2020
3835c33
Adding a few more tests around ChainSingle results.
reubenrybnik Jun 18, 2020
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
112 changes: 60 additions & 52 deletions types/underscore/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// Florian Keller <https://github.com/ffflorian>
// Regev Brody <https://github.com/regevbr>
// Piotr Błażejewicz <https://github.com/peterblazejewicz>
// Michael Ness <https://github.com/reubenrybnik>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8

Expand Down Expand Up @@ -70,18 +71,18 @@ declare module _ {
source: string;
}

interface Collection<T> { }

// Common interface between Arrays and jQuery objects
interface List<T> extends Collection<T> {
interface List<T> {
[index: number]: T;
length: number;
}

interface Dictionary<T> extends Collection<T> {
interface Dictionary<T> {
[index: string]: T;
}

type Collection<T> = List<T> | Dictionary<T>;

interface Predicate<T> {
(value: T): boolean;
}
Expand All @@ -106,22 +107,28 @@ declare module _ {
(prev: TResult, curr: T, key: string, list: Dictionary<T>): TResult;
}

type TypeOfList<V> = V extends _.List<infer T> ? T : never;

type TypeOfDictionary<V> = V extends _.Dictionary<infer T> ? T : never;

type TypeOfCollection<V> = V extends _.Collection<infer T> ? T : never;

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

interface Cancelable {
cancel(): void;
}

type TypeOfDictionary<T> = T extends _.Dictionary<infer V> ? V : never;

interface UnderscoreStatic {
/**
* Underscore OOP Wrapper, all Underscore functions that take an object
* as the first parameter can be invoked through this function.
* @param key First argument to Underscore object functions.
**/
<T>(value: _.List<T>): Underscore<T, _.List<T>>;
<T>(value: Array<T>): Underscore<T, Array<T>>;
<T extends TypeOfDictionary<V>, V extends _.Dictionary<any> = _.Dictionary<T>>(value: V): Underscore<T, V>;
<T>(value: T): Underscore<T>;
* Underscore OOP Wrapper, all Underscore functions that take an object
* as the first parameter can be invoked through this function.
* @param value First argument to Underscore object functions.
* @returns An Underscore wrapper around the supplied value.
**/
<T extends TypeOfList<V>, V extends List<any> = List<T>>(value: V): Underscore<T, V>;
<T extends TypeOfDictionary<V>, V extends Dictionary<any> = Dictionary<T>>(value: V): Underscore<T, V>;
<V>(value: V): Underscore<never, V>;

/* *************
* Collections *
Expand Down Expand Up @@ -1121,12 +1128,12 @@ declare module _ {
range(stop: number): number[];

/**
* Split an **array** into several arrays containing **count** or less elements
* of initial array.
* @param array The array to split
* @param count The maximum size of the inner arrays.
*/
chunk<T>(array: _.Collection<T>, count: number): (_.Collection<T>)[]
* Chunks a list into multiple arrays, each containing length or fewer items.
* @param list The list to split.
* @param length The maximum size of the inner arrays.
* @returns The chunked list.
**/
chunk<T>(list: List<T>, length: number): T[][]

/*************
* Functions *
Expand Down Expand Up @@ -4109,14 +4116,14 @@ declare module _ {
*********** */

/**
* Returns a wrapped object. Calling methods on this object will continue to return wrapped objects
* until value() is used.
* @param obj Object to chain.
* @return Wrapped `obj`.
**/
chain<T>(obj: T[]): _Chain<T, T[]>;
chain<T extends TypeOfDictionary<V>, V extends _.Dictionary<any> = _.Dictionary<T>>(obj: V): _Chain<T, V>;
chain<T extends {}>(obj: T): _Chain<T>;
* Returns a wrapped object. Calling methods on this object will continue to return wrapped objects
* until value() is used.
* @param value The object to chain.
* @returns An underscore chain wrapper around the supplied value.
**/
chain<T extends TypeOfList<V>, V extends List<any> = List<T>>(value: V): _Chain<T, V>;
chain<T extends TypeOfDictionary<V>, V extends Dictionary<any> = Dictionary<T>>(value: V): _Chain<T, V>;
chain<V>(value: V): _Chain<never, V>;

/**
* Current version
Expand Down Expand Up @@ -4628,10 +4635,11 @@ declare module _ {
range(): number[];

/**
* Wrapped type any[][].
* @see _.chunk
* Chunks a wrapped list into multiple arrays, each containing length or fewer items.
* @param length The maximum size of the inner arrays.
* @returns The chunked list.
**/
chunk(): any[][];
chunk(length: number): T[][];

/* ***********
* Functions *
Expand Down Expand Up @@ -5059,17 +5067,17 @@ declare module _ {
*********** */

/**
* Wrapped type `any`.
* @see _.chain
**/
* Returns a wrapped object. Calling methods on this object will continue to return wrapped objects
* until value() is used.
* @returns An underscore chain wrapper around the wrapped value.
**/
chain(): _Chain<T, V>;

/**
* Wrapped type `any`.
* Extracts the value of a wrapped object.
* @return Value of the wrapped object.
**/
value<TResult>(): TResult;
* Extracts the value of the wrapped object.
* @returns The value of the wrapped object.
**/
value(): V;
}

interface _Chain<T, V = T> {
Expand Down Expand Up @@ -5588,10 +5596,11 @@ declare module _ {
range(): _Chain<T>;

/**
* Wrapped type `any[][]`.
* @see _.chunk
* Chunks a wrapped list into multiple arrays, each containing length or fewer items.
* @param length The maximum size of the inner arrays.
* @returns The wrapped chunked list.
**/
chunk(): _Chain<T>;
chunk(length: number): _Chain<T[], T[][]>;

/* ***********
* Functions *
Expand Down Expand Up @@ -6106,20 +6115,19 @@ declare module _ {
*********** */

/**
* Wrapped type `any`.
* @see _.chain
**/
chain(): _Chain<T>;
* Returns a wrapped object. Calling methods on this object will continue to return wrapped objects
* until value() is used.
* @returns An underscore chain wrapper around the wrapped value.
**/
chain(): _Chain<T, V>;

/**
* Wrapped type `any`.
* @see _.value
**/
* Extracts the value of the wrapped object.
* @returns The value of the wrapped object.
**/
value(): V;
}
interface _ChainSingle<T> {
value(): T;
}

interface _ChainOfArrays<T> extends _Chain<T[]> {
flatten(shallow?: boolean): _Chain<T>;
}
Expand Down
139 changes: 139 additions & 0 deletions types/underscore/underscore-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,3 +659,142 @@ function strong_typed_values_tests() {

_.values<{title: string, value: number}>(dictionaryLike);
}

// tests for #7931 - verify that the result of a function like reduce that returns a singleton can be chained further
// $ExpectType number[]
_.chain([1, 2, 3])
.reduce((acc, x) => { acc.unshift(x); return acc; }, [] as number[])
.map(x => x + 1)
.value();

// $ExpectType boolean
_.chain([{ a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }])
.findWhere({ a: 1 })
.some(n => n === 2)
.value();

// $ExpectType number
_.chain([1, 2, 3, 4, 5, 6])
.chunk(3)
.first()
.reduce((aggregate, n) => aggregate + n, 0)
.value();

// common testing types and objects
interface SimpleStringObject {
a: string;
b: string;
}

interface SimpleStringObjectListWithExtraProperties extends _.List<SimpleStringObject> {
notAListProperty: boolean;
}

interface StronglyKeyedSimpleStringObjectDictionary extends _.Dictionary<SimpleStringObject> {
a: SimpleStringObject;
b: SimpleStringObject;
c: SimpleStringObject;
}

const simpleStringObjectArray: SimpleStringObject[] = [{ a: 'a', b: 'c' }, { a: 'b', b: 'b' }, { a: 'c', b: 'a' }];
const simpleStringObjectListWithExtraProperties: SimpleStringObjectListWithExtraProperties = { 0: { a: 'a', b: 'c' }, 1: { a: 'b', b: 'b' }, 2: { a: 'c', b: 'a' }, length: 3, notAListProperty: true };
const simpleStringObjectList: _.List<SimpleStringObject> = simpleStringObjectListWithExtraProperties;
const stronglyKeyedSimpleStringObjectDictionary: StronglyKeyedSimpleStringObjectDictionary = { a: { a: 'a', b: 'c' }, b: { a: 'b', b: 'b' }, c: { a: 'c', b: 'a' } };
const simpleStringObjectDictionary: _.Dictionary<SimpleStringObject> = stronglyKeyedSimpleStringObjectDictionary;

const simpleString = 'abc';

const simpleNumber = 7;

// Arrays

// chunk
{
const length = 2;

_.chunk(simpleStringObjectArray, length); // $ExpectType SimpleStringObject[][]
_(simpleStringObjectArray).chunk(length); // $ExpectType SimpleStringObject[][]
_.chain(simpleStringObjectArray).chunk(length); // $ExpectType _Chain<SimpleStringObject[], SimpleStringObject[][]>

_.chunk(simpleStringObjectList, length); // $ExpectType SimpleStringObject[][]
_(simpleStringObjectList).chunk(length); // $ExpectType SimpleStringObject[][]
_.chain(simpleStringObjectList).chunk(length); // $ExpectType _Chain<SimpleStringObject[], SimpleStringObject[][]>

_.chunk(simpleString, length); // $ExpectType string[][]
_(simpleString).chunk(length); // $ExpectType string[][]
_.chain(simpleString).chunk(length); // $ExpectType _Chain<string[], string[][]>
}

// OOP Style

// underscore
{
_(simpleStringObjectArray); // $ExpectType Underscore<SimpleStringObject, SimpleStringObject[]>

_(simpleStringObjectListWithExtraProperties) // $ExpectType Underscore<SimpleStringObject, SimpleStringObjectListWithExtraProperties>
_(simpleStringObjectList); // $ExpectType Underscore<SimpleStringObject, List<SimpleStringObject>>

_(stronglyKeyedSimpleStringObjectDictionary) // $ExpectType Underscore<SimpleStringObject, StronglyKeyedSimpleStringObjectDictionary>
_(simpleStringObjectDictionary); // $ExpectType Underscore<SimpleStringObject, Dictionary<SimpleStringObject>>

_(simpleString); // $ExpectType Underscore<string, string>
_(simpleNumber); // $ExpectType Underscore<never, number>
}

// value
// verify that the object type given to underscore is returned by value
{
_(simpleStringObjectArray).value(); // $ExpectType SimpleStringObject[]

_(simpleStringObjectListWithExtraProperties).value(); // $ExpectType SimpleStringObjectListWithExtraProperties
_(simpleStringObjectList).value(); // $ExpectType List<SimpleStringObject>

_(stronglyKeyedSimpleStringObjectDictionary).value(); // $ExpectType StronglyKeyedSimpleStringObjectDictionary
_(simpleStringObjectDictionary).value(); // $ExpectType Dictionary<SimpleStringObject>

_(simpleString).value(); // $ExpectType string
_(simpleNumber).value(); // $ExpectType number
}

// Chaining

// chain
// verify that the right chain item and value types are yielded by calls to chain
// these tests also check to make sure that _.chain() and _().chain() yield the same types
{
_.chain(simpleStringObjectArray); // $ExpectType _Chain<SimpleStringObject, SimpleStringObject[]>
_(simpleStringObjectArray).chain(); // $ExpectType _Chain<SimpleStringObject, SimpleStringObject[]>

_.chain(simpleStringObjectListWithExtraProperties); // $ExpectType _Chain<SimpleStringObject, SimpleStringObjectListWithExtraProperties>
_(simpleStringObjectListWithExtraProperties).chain(); // $ExpectType _Chain<SimpleStringObject, SimpleStringObjectListWithExtraProperties>

_.chain(simpleStringObjectList); // $ExpectType _Chain<SimpleStringObject, List<SimpleStringObject>>
_(simpleStringObjectList).chain(); // $ExpectType _Chain<SimpleStringObject, List<SimpleStringObject>>

_.chain(stronglyKeyedSimpleStringObjectDictionary); // $ExpectType _Chain<SimpleStringObject, StronglyKeyedSimpleStringObjectDictionary>
_(stronglyKeyedSimpleStringObjectDictionary).chain(); // $ExpectType _Chain<SimpleStringObject, StronglyKeyedSimpleStringObjectDictionary>

_.chain(simpleStringObjectDictionary); // $ExpectType _Chain<SimpleStringObject, Dictionary<SimpleStringObject>>
_(simpleStringObjectDictionary).chain(); // $ExpectType _Chain<SimpleStringObject, Dictionary<SimpleStringObject>>

_.chain(simpleString); // $ExpectType _Chain<string, string>
_(simpleString).chain(); // $ExpectType _Chain<string, string>

_.chain(simpleNumber); // $ExpectType _Chain<never, number>
_(simpleNumber).chain(); // $ExpectType _Chain<never, number>
}

// value
// verify that the object type given to chain is returned by value
{
_.chain(simpleStringObjectArray).value(); // $ExpectType SimpleStringObject[]

_.chain(simpleStringObjectListWithExtraProperties).value(); // $ExpectType SimpleStringObjectListWithExtraProperties
_.chain(simpleStringObjectList).value(); // $ExpectType List<SimpleStringObject>

_.chain(stronglyKeyedSimpleStringObjectDictionary).value(); // $ExpectType StronglyKeyedSimpleStringObjectDictionary
_.chain(simpleStringObjectDictionary).value(); // $ExpectType Dictionary<SimpleStringObject>

_.chain(simpleString).value(); // $ExpectType string
_.chain(simpleNumber).value(); // $ExpectType number
}