Skip to content

Commit

Permalink
Use power of Generics to infer types
Browse files Browse the repository at this point in the history
  • Loading branch information
Omid K. Rad committed Apr 21, 2014
1 parent d29aeca commit c13f866
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 51 deletions.
59 changes: 28 additions & 31 deletions underscore/underscore-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
declare var $;

_.each([1, 2, 3], (num) => alert(num.toString()));
_.each({ one: 1, two: 2, three: 3 }, (value) => alert(value.toString()));
_.each({ one: 1, two: 2, three: 3 }, (value, key) => alert(value.toString()));

_.map([1, 2, 3], (num) => num * 3);
_.map({ one: 1, two: 2, three: 3 }, (value: number, key?: string) => value * 3);
_.map({ one: 1, two: 2, three: 3 }, (value, key) => value * 3);

//var sum = _.reduce([1, 2, 3], (memo, num) => memo + num, 0); // https://typescript.codeplex.com/workitem/1960
var sum = _.reduce<number, number>([1, 2, 3], (memo, num) => memo + num, 0);
Expand All @@ -16,18 +16,20 @@ var list = [[0, 1], [2, 3], [4, 5]];
//var flat = _.reduceRight(list, (a, b) => a.concat(b), []); // https://typescript.codeplex.com/workitem/1960
var flat = _.reduceRight<number[], number[]>(list, (a, b) => a.concat(b), []);

var even = _.find<number>([1, 2, 3, 4, 5, 6], (num) => num % 2 == 0);
var even = _.find([1, 2, 3, 4, 5, 6], (num) => num % 2 == 0);

var evens = _.filter<number>([1, 2, 3, 4, 5, 6], (num) => num % 2 == 0);
var firstCapitalLetter = _.find({ a: 'a', b: 'B', c: 'C', d: 'd' }, l => l === l.toUpperCase());

var evens = _.filter([1, 2, 3, 4, 5, 6], (num) => num % 2 == 0);

var capitalLetters = _.filter({ a: 'a', b: 'B', c: 'C', d: 'd' }, l => l === l.toUpperCase());

var listOfPlays = [{ title: "Cymbeline", author: "Shakespeare", year: 1611 }, { title: "The Tempest", author: "Shakespeare", year: 1611 }, { title: "Other", author: "Not Shakespeare", year: 2012 }];
_.where(listOfPlays, { author: "Shakespeare", year: 1611 });

var odds = _.reject<number>([1, 2, 3, 4, 5, 6], (num) => num % 2 == 0);
var odds = _.reject([1, 2, 3, 4, 5, 6], (num) => num % 2 == 0);

//_.every([true, 1, null, 'yes'], _.identity); // https://typescript.codeplex.com/workitem/1960
_.every<any>([true, 1, null, 'yes'], _.identity);
_.every<{}>([true, 1, null, 'yes']);
_.every([true, 1, null, 'yes'], _.identity);

_.any([null, 0, 'yes', false]);

Expand All @@ -49,7 +51,7 @@ _.sortBy([1, 2, 3, 4, 5, 6], (num) => Math.sin(num));


_([1.3, 2.1, 2.4]).groupBy((e) => Math.floor(e));
_.groupBy([1.3, 2.1, 2.4], (num: number) => Math.floor(num).toString());
_.groupBy([1.3, 2.1, 2.4], (num) => Math.floor(num).toString());
_.groupBy(['one', 'two', 'three'], 'length');

_.indexBy(stooges, 'age')['40'].age;
Expand All @@ -59,7 +61,7 @@ _(stooges)
.indexBy('age')
.value()['40'].age;

_.countBy<number>([1, 2, 3, 4, 5], (num) => (num % 2 == 0) ? 'even' : 'odd');
_.countBy([1, 2, 3, 4, 5], (num) => (num % 2 == 0) ? 'even' : 'odd');

_.shuffle([1, 2, 3, 4, 5, 6]);

Expand Down Expand Up @@ -87,19 +89,19 @@ _.rest([5, 4, 3, 2, 1]);
_.compact([0, 1, false, 2, '', 3]);

_.flatten([1, 2, 3, 4]);
_.flatten([1, <any>[2]]);
_.flatten([1, [2]]);

// typescript doesn't like the elements being different
_.flatten([1, [2], <any>[3, <any>[[4]]]]);
_.flatten([1, [2], <any>[3, <any>[[4]]]], true);
_.flatten([1, [2], [3, [[4]]]]);
_.flatten([1, [2], [3, [[4]]]], true);
_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
_.uniq([1, 2, 1, 3, 1, 4]);
_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
var r = _.object<{ [key: string]: number }>(['moe', 'larry', 'curly'], [30, 40, 50]);
_.object([[<any>'moe', 30], [<any>'larry', 40], [<any>'curly', 50]]);
var r = _.object(['moe', 'larry', 'curly'], [30, 40, 50]);
_.object([['moe', 30], ['larry', 40], ['curly', 50]]);
_.indexOf([1, 2, 3], 2);
_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
_.sortedIndex([10, 20, 30, 40, 50], 35);
Expand Down Expand Up @@ -183,18 +185,15 @@ _.clone(['i', 'am', 'an', 'object!']);

_([1, 2, 3, 4])
.chain()
.filter((num: number) => {
return num % 2 == 0;
}).tap(alert)
.map((num: number) => {
return num * num;
})
.filter((num) => { return num % 2 == 0; })
.tap(alert)
.map((num) => { return num * num; })
.value();

_.chain([1, 2, 3, 200])
.filter(function (num: number) { return num % 2 == 0; })
.filter((num) => { return num % 2 == 0; })
.tap(alert)
.map(function (num: number) { return num * num })
.map((num) => { return num * num; })
.value();

_.has({ a: 1, b: 2, c: 3 }, "b");
Expand Down Expand Up @@ -259,7 +258,7 @@ var moe2 = { name: 'moe' };
moe2 === _.identity(moe);

var genie;
var r2 = _.times<number>(3, (n) => { return n * n });
var r2 = _.times(3, (n) => { return n * n });
_(3).times(function (n) { genie.grantWishNumber(n); });

_.random(0, 100);
Expand Down Expand Up @@ -301,29 +300,27 @@ _(['test', 'test']).pick(['test2', 'test2']);
//////////////// Chain Tests
function chain_tests() {
// https://typescript.codeplex.com/workitem/1960
var numArray: number[] = _.chain([1, 2, 3, 4, 5, 6, 7, 8])
var numArray = _.chain([1, 2, 3, 4, 5, 6, 7, 8])
.filter(num => num % 2 == 0)
.map(num => num * num)
.value();

var strArray: string[] = _([1, 2, 3, 4])
var strArray = _([1, 2, 3, 4])
.chain()
.filter(num => num % 2 == 0)
.tap(alert)
.map(num => "string" + num)
.value();

var n : number = _.chain([1, 2, 3, 200])
var n = _.chain([1, 2, 3, 200])
.filter(num => num % 2 == 0)
.tap(alert)
.map(num => num * num)
.max()
.value();

//If using alternate definition of map (~ line 2200), .value returns any
// because.map matches _Chain <number[]> as opposed to _ChainOfArrays <number>, which breaks typing on flatten
var hoverOverValueShouldBeNumberNotAny : number = _([1, 2, 3]).chain()
.map(num=> [num, num + 1])
var hoverOverValueShouldBeNumberNotAny = _([1, 2, 3]).chain()
.map(num => [num, num + 1])
.flatten()
.find(num => num % 2 == 0)
.value();
Expand Down
60 changes: 40 additions & 20 deletions underscore/underscore.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ declare module _ {

/**
* underscore.js template settings, set templateSettings or pass as an argument
* to 'template()' to overide defaults.
* to 'template()' to override defaults.
**/
interface TemplateSettings {
/**
Expand Down Expand Up @@ -200,7 +200,7 @@ interface UnderscoreStatic {

/**
* The right-associative version of reduce. Delegates to the JavaScript 1.8 version of
* reduceRight, if it exists. Foldr is not as useful in JavaScript as it would be in a
* reduceRight, if it exists. `foldr` is not as useful in JavaScript as it would be in a
* language with lazy evaluation.
* @param list Reduces the elements of this array.
* @param iterator Reduce iterator function for each element in `list`.
Expand Down Expand Up @@ -233,7 +233,15 @@ interface UnderscoreStatic {
* @return The first acceptable found element in `list`, if nothing is found undefined/null is returned.
**/
find<T>(
list: _.Collection<T>,
list: _.List<T>,
iterator: _.ListIterator<T, boolean>,
context?: any): T;

/**
* @see _.find
**/
find<T>(
list: _.Dictionary<T>,
iterator: _.ListIterator<T, boolean>,
context?: any): T;

Expand All @@ -254,7 +262,15 @@ interface UnderscoreStatic {
* @return The filtered list of elements.
**/
filter<T>(
list: _.Collection<T>,
list: _.List<T>,
iterator: _.ListIterator<T, boolean>,
context?: any): T[];

/**
* @see _.filter
**/
filter<T>(
list: _.Dictionary<T>,
iterator: _.ListIterator<T, boolean>,
context?: any): T[];

Expand Down Expand Up @@ -297,7 +313,15 @@ interface UnderscoreStatic {
* @return The rejected list of elements.
**/
reject<T>(
list: _.Collection<T>,
list: _.List<T>,
iterator: _.ListIterator<T, boolean>,
context?: any): T[];

/**
* @see _.reject
**/
reject<T>(
list: _.Dictionary<T>,
iterator: _.ListIterator<T, boolean>,
context?: any): T[];

Expand Down Expand Up @@ -497,7 +521,7 @@ interface UnderscoreStatic {
* @return An object with the group names as properties where each property contains the number of elements in that group.
**/
countBy<T>(
list: _.Collection<T>,
list: _.List<T>,
iterator?: _.ListIterator<T, any>,
context?: any): _.Dictionary<number>;

Expand All @@ -506,7 +530,7 @@ interface UnderscoreStatic {
* @param iterator Function name
**/
countBy<T>(
list: _.Collection<T>,
list: _.Dictionary<T>,
iterator: string,
context?: any): _.Dictionary<number>;

Expand Down Expand Up @@ -603,7 +627,7 @@ interface UnderscoreStatic {
/**
* Returns everything but the last entry of the array. Especially useful on the arguments object.
* Pass n to exclude the last n elements from the result.
* @param array Retreive all elements except the last `n`.
* @param array Retrieve all elements except the last `n`.
* @param n Leaves this many elements behind, optional.
* @return Returns everything but the last `n` elements of `array`.
**/
Expand Down Expand Up @@ -711,7 +735,7 @@ interface UnderscoreStatic {
* advance that the array is sorted, passing true for isSorted will run a much faster algorithm. If
* you want to compute unique items based on a transformation, pass an iterator function.
* @param array Array to remove duplicates from.
* @param isSorted True if `array` is already sorted, optiona, default = false.
* @param isSorted True if `array` is already sorted, optional, default = false.
* @param iterator Transform the elements of `array` before comparisons for uniqueness.
* @param context 'this' object in `iterator`, optional.
* @return Copy of `array` where all elements are unique.
Expand Down Expand Up @@ -817,7 +841,7 @@ interface UnderscoreStatic {
* @param array The array to search for the last index of `value`.
* @param value The value to search for within `array`.
* @param from The starting index for the search, optional.
* @return The index of the last occurance of `value` within `array`.
* @return The index of the last occurrence of `value` within `array`.
**/
lastIndexOf<T>(
array: _.List<T>,
Expand Down Expand Up @@ -918,7 +942,7 @@ interface UnderscoreStatic {
/**
* Much like setTimeout, invokes function after wait milliseconds. If you pass the optional arguments,
* they will be forwarded on to the function when it is invoked.
* @param fn Function to delay `waitMS` amount of ms.
* @param func Function to delay `waitMS` amount of ms.
* @param wait The amount of milliseconds to delay `fn`.
* @arguments Additional arguments to pass to `fn`.
**/
Expand Down Expand Up @@ -954,7 +978,7 @@ interface UnderscoreStatic {
* if you call it again any number of times during the wait period, as soon as that period is over.
* If you'd like to disable the leading-edge call, pass {leading: false}, and if you'd like to disable
* the execution on the trailing-edge, pass {trailing: false}.
* @param fn Function to throttle `waitMS` ms.
* @param func Function to throttle `waitMS` ms.
* @param wait The number of milliseconds to wait before `fn` can be invoked again.
* @param options Allows for disabling execution of the throttled function on either the leading or trailing edge.
* @return `fn` with a throttle of `wait`.
Expand Down Expand Up @@ -1030,14 +1054,14 @@ interface UnderscoreStatic {

/**
* Retrieve all the names of the object's properties.
* @param object Retreive the key or property names from this object.
* @param object Retrieve the key or property names from this object.
* @return List of all the property names on `object`.
**/
keys(object: any): string[];

/**
* Return all of the values of the object's properties.
* @param object Retreive the values of all the properties on this object.
* @param object Retrieve the values of all the properties on this object.
* @return List of all the values on `object`.
**/
values(object: any): any[];
Expand Down Expand Up @@ -2233,9 +2257,7 @@ interface _Chain<T> {
* Wrapped type `any[]`.
* @see _.map
**/
map<TArray>(iterator: (value: T, index: number, list: T[]) => TArray[], context?: any): _ChainOfArrays<TArray>;
//Not sure why this won't work, might be a TypeScript error?
//map<TArray>(iterator: _.ListIterator<T, TArray[]>, context?: any): _ChainOfArrays<TArray>;
map<TArray>(iterator: _.ListIterator<T, TArray[]>, context?: any): _ChainOfArrays<TArray>;

/**
* Wrapped type `any[]`.
Expand All @@ -2247,9 +2269,7 @@ interface _Chain<T> {
* Wrapped type `any[]`.
* @see _.map
**/
map<TArray>(iterator: (element: T, key: string, list: any) => TArray[], context?: any): _ChainOfArrays<TArray>;
//Not sure why this won't work, might be a TypeScript error?
//map<TArray>(iterator: _.ObjectIterator<T, TArray[]>, context?: any): _ChainOfArrays<TArray>;
map<TArray>(iterator: _.ObjectIterator<T, TArray[]>, context?: any): _ChainOfArrays<TArray>;

/**
* Wrapped type `any[]`.
Expand Down

0 comments on commit c13f866

Please sign in to comment.