// Define the "filter map" operator. interface Operator<T, U> { ( value: T, index: number, values: T[] ) : U; } // If we want to augment one of the global / native modules, like Array, we have to use // the special "global" module reference. declare global { // If we want to add INSTANCE METHODS to one of the native classes, we have // to "declaration merge" an interface into the existing class. interface Array<T> { filterMap<T, U>( operator: Operator<T, U>, context?: any ) : U[]; } } // I map the contextual collection onto another collection by appending defined results // of the operation onto the mapped collection. This means that "undefined" results will // be omitted from the mapped collection. // -- // CAUTION: Augmentations for the global scope can only be directly nested in external // modules or ambient module declarations. As such, we are EXPORTING this function to // force this file to become an "external module" (one that imports or exports other // modules). export function filterMap<T, U>( operator: Operator<T, U>, context: any = null ) : U[] { var results = this.reduce( ( reduction: U[], value: T, index: number, values: T[] ) : U[] => { var mappedValue = operator.call( context, value, index, values ); if ( mappedValue !== undefined ) { reduction.push( mappedValue ); } return( reduction ); }, [] ); return( results ); }; // Protect against conflicting definitions. Since each module in Node.js is evaluated // only once (and then cached in memory), we should never hit this line more than once // (no matter how many times we include it). As such, the only way this method would // already be defined is if another module has injected it without knowing that this // module would follow-suit. if ( Array.prototype.filterMap ) { throw( new Error( "Array.prototype.filterMap is already defined - overriding it will be dangerous." ) ); } // Augment the global Array prototype (ie, add an instance method). Array.prototype.filterMap = filterMap;