1- function detect ( enumerable , callback ) {
2- if ( enumerable . detect ) {
1+ interface Detectable < T > {
2+ detect ( cb : ( val : T ) => boolean ) : T
3+ }
4+
5+ interface HasLength < T > {
6+ [ key : number ] : T
7+ length : number
8+ }
9+
10+ export function detect < T > ( enumerable : Detectable < T > | HasLength < T > , callback : ( val : T ) => boolean ) : T | undefined {
11+ if ( 'detect' in enumerable ) {
312 return enumerable . detect ( callback )
413 } else {
514 for ( let i = 0 ; i < enumerable . length ; i ++ ) {
@@ -10,8 +19,12 @@ function detect(enumerable, callback) {
1019 }
1120}
1221
13- function any ( enumerable , callback ) {
14- if ( enumerable . any ) {
22+ interface Anyable < T > {
23+ any ( cb : ( val : T ) => boolean ) : boolean
24+ }
25+
26+ export function any < T > ( enumerable : Anyable < T > | HasLength < T > , callback : ( val : T ) => boolean ) : boolean {
27+ if ( 'any' in enumerable ) {
1528 return enumerable . any ( callback )
1629 }
1730
@@ -24,8 +37,12 @@ function any(enumerable, callback) {
2437 return false
2538}
2639
27- function every ( enumerable , callback ) {
28- if ( enumerable . every ) {
40+ interface Everyable < T > {
41+ every ( cb : ( val : T ) => boolean ) : boolean
42+ }
43+
44+ export function every < T > ( enumerable : Everyable < T > | HasLength < T > , callback : ( val : T ) => boolean ) : boolean {
45+ if ( 'every' in enumerable ) {
2946 return enumerable . every ( callback )
3047 }
3148
@@ -34,20 +51,25 @@ function every(enumerable, callback) {
3451 return false
3552 }
3653 }
54+
3755 return true
3856}
3957
40- function toArray ( arrayLike ) {
58+ export function toArray < T > ( arrayLike : ArrayLike < T > ) : T [ ] {
4159 return Array . prototype . slice . call ( arrayLike )
4260}
4361
62+ interface ForEachable < T > {
63+ forEach ( cb : ( val : T , idx : number ) => void ) : void
64+ }
65+
4466/**
4567 * Useful for array-like things that aren't
4668 * actually arrays, like NodeList
4769 * @private
4870 */
49- function forEach ( enumerable , callback ) {
50- if ( enumerable . forEach ) {
71+ export function forEach < T > ( enumerable : ForEachable < T > | HasLength < T > , callback : ( val : T , idx : number ) => void ) : void {
72+ if ( ' forEach' in enumerable ) {
5173 enumerable . forEach ( callback )
5274 } else {
5375 for ( let i = 0 ; i < enumerable . length ; i ++ ) {
@@ -56,56 +78,68 @@ function forEach(enumerable, callback) {
5678 }
5779}
5880
59- function filter ( enumerable , conditionFn ) {
60- const filtered = [ ]
81+ export function filter < T > ( enumerable : ArrayLike < T > , conditionFn : ( val : T ) => boolean ) {
82+ const filtered : T [ ] = [ ]
83+
6184 forEach ( enumerable , i => {
6285 if ( conditionFn ( i ) ) {
6386 filtered . push ( i )
6487 }
6588 } )
89+
6690 return filtered
6791}
6892
6993/**
7094 * @return {Integer } the number of items that are the same, starting from the 0th index, in a and b
7195 * @private
7296 */
73- function commonItemLength ( listA , listB ) {
97+ export function commonItemLength ( listA : ArrayLike < unknown > , listB : ArrayLike < unknown > ) {
7498 let offset = 0
99+
75100 while ( offset < listA . length && offset < listB . length ) {
76101 if ( listA [ offset ] !== listB [ offset ] ) {
77102 break
78103 }
79104 offset ++
80105 }
106+
81107 return offset
82108}
83109
84110/**
85111 * @return {Array } the items that are the same, starting from the 0th index, in a and b
86112 * @private
87113 */
88- function commonItems ( listA , listB ) {
114+ export function commonItems < T > ( listA : T [ ] , listB : T [ ] ) : T [ ] {
89115 let offset = 0
116+
90117 while ( offset < listA . length && offset < listB . length ) {
91118 if ( listA [ offset ] !== listB [ offset ] ) {
92119 break
93120 }
94121 offset ++
95122 }
123+
96124 return listA . slice ( 0 , offset )
97125}
98126
99127// return new array without falsy items like ruby's `compact`
100- function compact ( enumerable ) {
128+ export function compact < T > ( enumerable : ArrayLike < T > ) {
101129 return filter ( enumerable , i => ! ! i )
102130}
103131
104- function reduce ( enumerable , callback , initialValue ) {
132+ export function reduce < T , U > (
133+ enumerable : ArrayLike < T > ,
134+ callback : ( prev : U , val : T , index : number ) => U ,
135+ initialValue : U
136+ ) : U {
105137 let previousValue = initialValue
138+
106139 forEach ( enumerable , ( val , index ) => {
107140 previousValue = callback ( previousValue , val , index )
108141 } )
142+
109143 return previousValue
110144}
111145
@@ -114,29 +148,34 @@ function reduce(enumerable, callback, initialValue) {
114148 * @return {Object } {key1:value1, key2:value2, ...}
115149 * @private
116150 */
117- function kvArrayToObject ( array ) {
118- const obj = { }
151+ export function kvArrayToObject < T > ( array : ( T | string ) [ ] ) : { [ key : string ] : T } {
152+ const obj : { [ key : string ] : T } = { }
153+
119154 for ( let i = 0 ; i < array . length ; i += 2 ) {
120155 let [ key , value ] = [ array [ i ] , array [ i + 1 ] ]
121- obj [ key ] = value
156+ obj [ key as string ] = value as T
122157 }
158+
123159 return obj
124160}
125161
126- function objectToSortedKVArray ( obj ) {
127- const keys = Object . keys ( obj ) . sort ( )
128- const result = [ ]
162+ export function objectToSortedKVArray < T extends { } > ( obj : T ) : ( keyof T | T [ keyof T ] ) [ ] {
163+ const keys = Object . keys ( obj ) . sort ( ) as ( keyof T ) [ ]
164+ const result : ( keyof T | T [ keyof T ] ) [ ] = [ ]
165+
129166 keys . forEach ( k => {
130167 result . push ( k )
131168 result . push ( obj [ k ] )
132169 } )
170+
133171 return result
134172}
135173
136174// check shallow equality of two non-nested arrays
137- function isArrayEqual ( arr1 , arr2 ) {
138- let l1 = arr1 . length ,
139- l2 = arr2 . length
175+ export function isArrayEqual < T > ( arr1 : ArrayLike < T > , arr2 : ArrayLike < T > ) : boolean {
176+ let l1 = arr1 . length
177+ let l2 = arr2 . length
178+
140179 if ( l1 !== l2 ) {
141180 return false
142181 }
@@ -146,42 +185,26 @@ function isArrayEqual(arr1, arr2) {
146185 return false
147186 }
148187 }
188+
149189 return true
150190}
151191
152192// return an object with only the valid keys
153- function filterObject ( object , validKeys = [ ] ) {
154- let result = { }
193+ export function filterObject < T > ( object : T , validKeys : string [ ] = [ ] ) {
194+ let result : { [ key : string ] : unknown } = { }
195+
155196 forEach (
156197 filter ( Object . keys ( object ) , key => validKeys . indexOf ( key ) !== - 1 ) ,
157- key => ( result [ key ] = object [ key ] )
198+ key => ( result [ key ] = ( object as any ) [ key ] )
158199 )
200+
159201 return result
160202}
161203
162- function contains ( array , item ) {
204+ export function contains < T > ( array : T [ ] , item : T ) : boolean {
163205 return array . indexOf ( item ) !== - 1
164206}
165207
166- function values ( object ) {
167- return Object . keys ( object ) . map ( key => object [ key ] )
168- }
169-
170- export {
171- detect ,
172- forEach ,
173- any ,
174- every ,
175- filter ,
176- commonItemLength ,
177- commonItems ,
178- compact ,
179- reduce ,
180- objectToSortedKVArray ,
181- kvArrayToObject ,
182- isArrayEqual ,
183- toArray ,
184- filterObject ,
185- contains ,
186- values ,
208+ export function values < T extends { } > ( object : T ) : T [ keyof T ] [ ] {
209+ return ( Object . keys ( object ) as ( keyof T ) [ ] ) . map ( key => object [ key ] )
187210}
0 commit comments