@@ -130,37 +130,62 @@ namespace ts {
130130 return - 1 ;
131131 }
132132
133- export function countWhere < T > ( array : T [ ] , predicate : ( x : T ) => boolean ) : number {
133+ export function countWhere < T > ( array : T [ ] , predicate : ( x : T , i : number ) => boolean ) : number {
134134 let count = 0 ;
135135 if ( array ) {
136- for ( const v of array ) {
137- if ( predicate ( v ) ) {
136+ for ( let i = 0 ; i < array . length ; i ++ ) {
137+ const v = array [ i ] ;
138+ if ( predicate ( v , i ) ) {
138139 count ++ ;
139140 }
140141 }
141142 }
142143 return count ;
143144 }
144145
145- export function filter < T > ( array : T [ ] , f : ( x : T ) => boolean ) : T [ ] {
146+ export function filter < T , U extends T > ( array : T [ ] , f : ( x : T , i : number ) => x is U ) : U [ ] ;
147+ export function filter < T > ( array : T [ ] , f : ( x : T , i : number ) => boolean ) : T [ ] ;
148+ export function filter < T > ( array : T [ ] , f : ( x : T , i : number ) => boolean ) : T [ ] {
146149 let result : T [ ] ;
147150 if ( array ) {
148151 result = [ ] ;
149- for ( const item of array ) {
150- if ( f ( item ) ) {
151- result . push ( item ) ;
152+ for ( let i = 0 ; i < array . length ; i ++ ) {
153+ const v = array [ i ] ;
154+ if ( f ( v , i ) ) {
155+ result . push ( v ) ;
152156 }
153157 }
154158 }
155159 return result ;
156160 }
157161
158- export function map < T , U > ( array : T [ ] , f : ( x : T ) => U ) : U [ ] {
162+ export function map < T , U > ( array : T [ ] , f : ( x : T , i : number ) => U ) : U [ ] {
159163 let result : U [ ] ;
160164 if ( array ) {
161165 result = [ ] ;
162- for ( const v of array ) {
163- result . push ( f ( v ) ) ;
166+ for ( let i = 0 ; i < array . length ; i ++ ) {
167+ const v = array [ i ] ;
168+ result . push ( f ( v , i ) ) ;
169+ }
170+ }
171+ return result ;
172+ }
173+
174+ /**
175+ * Maps an array. If the mapped value is an array, it is spread into the result.
176+ */
177+ export function flatMap < T , U > ( array : T [ ] , f : ( x : T , i : number ) => U | U [ ] ) : U [ ] {
178+ let result : U [ ] ;
179+ if ( array ) {
180+ result = [ ] ;
181+ for ( let i = 0 ; i < array . length ; i ++ ) {
182+ const v = array [ i ] ;
183+ const ar = f ( v , i ) ;
184+ if ( ar ) {
185+ // We cast to <U> here to leverage the behavior of Array#concat
186+ // which will append a single value here.
187+ result = result . concat ( < U [ ] > ar ) ;
188+ }
164189 }
165190 }
166191 return result ;
@@ -172,18 +197,6 @@ namespace ts {
172197 return [ ...array1 , ...array2 ] ;
173198 }
174199
175- export function append < T > ( array : T [ ] , value : T ) : T [ ] {
176- if ( value === undefined ) return array ;
177- if ( ! array || ! array . length ) return [ value ] ;
178- return [ ...array , value ] ;
179- }
180-
181- export function prepend < T > ( array : T [ ] , value : T ) : T [ ] {
182- if ( value === undefined ) return array ;
183- if ( ! array || ! array . length ) return [ value ] ;
184- return [ value , ...array ] ;
185- }
186-
187200 export function deduplicate < T > ( array : T [ ] ) : T [ ] {
188201 let result : T [ ] ;
189202 if ( array ) {
@@ -197,6 +210,27 @@ namespace ts {
197210 return result ;
198211 }
199212
213+ /**
214+ * Compacts an array, removing any falsey elements.
215+ */
216+ export function compact < T > ( array : T [ ] ) : T [ ] {
217+ let result : T [ ] ;
218+ if ( array ) {
219+ for ( let i = 0 ; i < array . length ; i ++ ) {
220+ const v = array [ i ] ;
221+ if ( result || ! v ) {
222+ if ( ! result ) {
223+ result = array . slice ( 0 , i ) ;
224+ }
225+ if ( v ) {
226+ result . push ( v ) ;
227+ }
228+ }
229+ }
230+ }
231+ return result || array ;
232+ }
233+
200234 export function sum ( array : any [ ] , prop : string ) : number {
201235 let result = 0 ;
202236 for ( const v of array ) {
@@ -223,15 +257,25 @@ namespace ts {
223257 return true ;
224258 }
225259
260+ export function firstOrUndefined < T > ( array : T [ ] ) : T {
261+ return array && array . length > 0
262+ ? array [ 0 ]
263+ : undefined ;
264+ }
265+
266+ export function singleOrUndefined < T > ( array : T [ ] ) : T {
267+ return array && array . length === 1
268+ ? array [ 0 ]
269+ : undefined ;
270+ }
271+
226272 /**
227273 * Returns the last element of an array if non-empty, undefined otherwise.
228274 */
229275 export function lastOrUndefined < T > ( array : T [ ] ) : T {
230- if ( array . length === 0 ) {
231- return undefined ;
232- }
233-
234- return array [ array . length - 1 ] ;
276+ return array && array . length > 0
277+ ? array [ array . length - 1 ]
278+ : undefined ;
235279 }
236280
237281 /**
@@ -263,9 +307,9 @@ namespace ts {
263307 return ~ low ;
264308 }
265309
266- export function reduceLeft < T , U > ( array : T [ ] , f : ( memo : U , value : T ) => U , initial : U ) : U ;
267- export function reduceLeft < T > ( array : T [ ] , f : ( memo : T , value : T ) => T ) : T ;
268- export function reduceLeft < T > ( array : T [ ] , f : ( memo : T , value : T ) => T , initial ?: T ) : T {
310+ export function reduceLeft < T , U > ( array : T [ ] , f : ( memo : U , value : T , i : number ) => U , initial : U ) : U ;
311+ export function reduceLeft < T > ( array : T [ ] , f : ( memo : T , value : T , i : number ) => T ) : T ;
312+ export function reduceLeft < T > ( array : T [ ] , f : ( memo : T , value : T , i : number ) => T , initial ?: T ) : T {
269313 if ( array ) {
270314 const count = array . length ;
271315 if ( count > 0 ) {
@@ -279,7 +323,7 @@ namespace ts {
279323 result = initial ;
280324 }
281325 while ( pos < count ) {
282- result = f ( result , array [ pos ] ) ;
326+ result = f ( result , array [ pos ] , pos ) ;
283327 pos ++ ;
284328 }
285329 return result ;
@@ -288,9 +332,9 @@ namespace ts {
288332 return initial ;
289333 }
290334
291- export function reduceRight < T , U > ( array : T [ ] , f : ( memo : U , value : T ) => U , initial : U ) : U ;
292- export function reduceRight < T > ( array : T [ ] , f : ( memo : T , value : T ) => T ) : T ;
293- export function reduceRight < T > ( array : T [ ] , f : ( memo : T , value : T ) => T , initial ?: T ) : T {
335+ export function reduceRight < T , U > ( array : T [ ] , f : ( memo : U , value : T , i : number ) => U , initial : U ) : U ;
336+ export function reduceRight < T > ( array : T [ ] , f : ( memo : T , value : T , i : number ) => T ) : T ;
337+ export function reduceRight < T > ( array : T [ ] , f : ( memo : T , value : T , i : number ) => T , initial ?: T ) : T {
294338 if ( array ) {
295339 let pos = array . length - 1 ;
296340 if ( pos >= 0 ) {
@@ -303,7 +347,7 @@ namespace ts {
303347 result = initial ;
304348 }
305349 while ( pos >= 0 ) {
306- result = f ( result , array [ pos ] ) ;
350+ result = f ( result , array [ pos ] , pos ) ;
307351 pos -- ;
308352 }
309353 return result ;
0 commit comments