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
16 changes: 7 additions & 9 deletions types/underscore/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,13 @@ declare module _ {
(prev: TResult, curr: T, key: string, list: Dictionary<T>): TResult;
}

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

type TypeOfDictionary<V> = V extends _.Dictionary<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 TypeOfCollection<V> = V extends List<infer T> ? T
: V extends Dictionary<infer T> ? T
: never;

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

Expand All @@ -126,9 +128,7 @@ declare module _ {
* @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>;
<V>(value: V): Underscore<TypeOfCollection<V>, V>;

/* *************
* Collections *
Expand Down Expand Up @@ -4121,9 +4121,7 @@ declare module _ {
* @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>;
chain<V>(value: V): _Chain<TypeOfCollection<V>, V>;

/**
* Current version
Expand Down
127 changes: 78 additions & 49 deletions types/underscore/underscore-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -681,79 +681,103 @@ _.chain([1, 2, 3, 4, 5, 6])
.value();

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

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

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

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 stringRecordArray: StringRecord[] = [{ a: 'a', b: 'c' }, { a: 'b', b: 'b' }, { a: 'c', b: 'a' }];
const stringRecordAugmentedList: StringRecordAugmentedList = { 0: { a: 'a', b: 'c' }, 1: { a: 'b', b: 'b' }, 2: { a: 'c', b: 'a' }, length: 3, notAListProperty: true };
const stringRecordList: _.List<StringRecord> = stringRecordAugmentedList;
const stringRecordExplicitDictionary: StringRecordExplicitDictionary = { a: { a: 'a', b: 'c' }, b: { a: 'b', b: 'b' }, c: { a: 'c', b: 'a' } };
const stringRecordDictionary: _.Dictionary<StringRecord> = stringRecordExplicitDictionary;

const simpleString = 'abc';

const simpleNumber = 7;

declare const mixedIterabilityValue: number | 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> { }

interface UnderscoreTypeExtractor {
<T, V>(chainResult: _.Underscore<T, V>): UnderscoreType<V, T>;
}

declare const extractUnderscoreTypes: UnderscoreTypeExtractor;

interface ChainType<TWrappedValue, TItemType> { }

interface ChainTypeExtractor {
<T, V>(chainResult: _._Chain<T, V>): ChainType<V, T>;
}

declare const extractChainTypes: ChainTypeExtractor;

// Arrays

// chunk
{
const length = 2;

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

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

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

// OOP Style

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

extractUnderscoreTypes(_(stringRecordAugmentedList)); // $ExpectType UnderscoreType<StringRecordAugmentedList, StringRecord>
extractUnderscoreTypes(_(stringRecordList)); // $ExpectType UnderscoreType<List<StringRecord>, StringRecord>

_(simpleStringObjectListWithExtraProperties) // $ExpectType Underscore<SimpleStringObject, SimpleStringObjectListWithExtraProperties>
_(simpleStringObjectList); // $ExpectType Underscore<SimpleStringObject, List<SimpleStringObject>>
extractUnderscoreTypes(_(stringRecordExplicitDictionary)); // $ExpectType UnderscoreType<StringRecordExplicitDictionary, StringRecord>
extractUnderscoreTypes(_(stringRecordDictionary)); // $ExpectType UnderscoreType<Dictionary<StringRecord>, StringRecord>

_(stronglyKeyedSimpleStringObjectDictionary) // $ExpectType Underscore<SimpleStringObject, StronglyKeyedSimpleStringObjectDictionary>
_(simpleStringObjectDictionary); // $ExpectType Underscore<SimpleStringObject, Dictionary<SimpleStringObject>>
extractUnderscoreTypes(_(simpleString)); // $ExpectType UnderscoreType<string, string>
extractUnderscoreTypes(_(simpleNumber)); // $ExpectType UnderscoreType<number, never>

_(simpleString); // $ExpectType Underscore<string, string>
_(simpleNumber); // $ExpectType Underscore<never, number>
extractUnderscoreTypes(_(mixedIterabilityValue)); // $ExpectType UnderscoreType<number | number[], number>
}

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

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

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

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

_(mixedIterabilityValue).value(); // $ExpectType number | number[]
}

// Chaining
Expand All @@ -762,39 +786,44 @@ const simpleNumber = 7;
// 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[]>
extractChainTypes(_.chain(stringRecordArray)); // $ExpectType ChainType<StringRecord[], StringRecord>
extractChainTypes(_(stringRecordArray).chain()); // $ExpectType ChainType<StringRecord[], StringRecord>

extractChainTypes(_.chain(stringRecordAugmentedList)); // $ExpectType ChainType<StringRecordAugmentedList, StringRecord>
extractChainTypes(_(stringRecordAugmentedList).chain()); // $ExpectType ChainType<StringRecordAugmentedList, StringRecord>

_.chain(simpleStringObjectListWithExtraProperties); // $ExpectType _Chain<SimpleStringObject, SimpleStringObjectListWithExtraProperties>
_(simpleStringObjectListWithExtraProperties).chain(); // $ExpectType _Chain<SimpleStringObject, SimpleStringObjectListWithExtraProperties>
extractChainTypes(_.chain(stringRecordList)); // $ExpectType ChainType<List<StringRecord>, StringRecord>
extractChainTypes(_(stringRecordList).chain()); // $ExpectType ChainType<List<StringRecord>, StringRecord>

_.chain(simpleStringObjectList); // $ExpectType _Chain<SimpleStringObject, List<SimpleStringObject>>
_(simpleStringObjectList).chain(); // $ExpectType _Chain<SimpleStringObject, List<SimpleStringObject>>
extractChainTypes(_.chain(stringRecordExplicitDictionary)); // $ExpectType ChainType<StringRecordExplicitDictionary, StringRecord>
extractChainTypes(_(stringRecordExplicitDictionary).chain()); // $ExpectType ChainType<StringRecordExplicitDictionary, StringRecord>

_.chain(stronglyKeyedSimpleStringObjectDictionary); // $ExpectType _Chain<SimpleStringObject, StronglyKeyedSimpleStringObjectDictionary>
_(stronglyKeyedSimpleStringObjectDictionary).chain(); // $ExpectType _Chain<SimpleStringObject, StronglyKeyedSimpleStringObjectDictionary>
extractChainTypes(_.chain(stringRecordDictionary)); // $ExpectType ChainType<Dictionary<StringRecord>, StringRecord>
extractChainTypes(_(stringRecordDictionary).chain()); // $ExpectType ChainType<Dictionary<StringRecord>, StringRecord>

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

_.chain(simpleString); // $ExpectType _Chain<string, string>
_(simpleString).chain(); // $ExpectType _Chain<string, string>
extractChainTypes(_.chain(simpleNumber)); // $ExpectType ChainType<number, never>
extractChainTypes(_(simpleNumber).chain()); // $ExpectType ChainType<number, never>

_.chain(simpleNumber); // $ExpectType _Chain<never, number>
_(simpleNumber).chain(); // $ExpectType _Chain<never, number>
extractChainTypes(_.chain(mixedIterabilityValue)); // $ExpectType ChainType<number | number[], number>
extractChainTypes(_(mixedIterabilityValue).chain()); // $ExpectType ChainType<number | number[], number>
}

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

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

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

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

_.chain(mixedIterabilityValue).value(); // $ExpectType number | number[]
}