I have augmented the Array prototype that mimics C# LINQ, which allows us to write complex array manipulation logic into really readable and maintainable code. It currently works really well when used in a single project like this:
ArrayExtensions.d.ts:
declare interface Array<T> {
aggregate<TSource>(this: TSource[], seed: TSource, func: (accumulated: TSource, source: TSource) => TSource): TSource;
all<T>(this: T[], predicate: (item: T) => boolean): boolean;
any<T>(this: T[], predicate: (item: T) => boolean): boolean;
append<T>(this: T[], value: T | T[]): T[];
apply<T>(this: T[], action?: ((item: T) => void)): T[];
average<T>(this: T[], callback: (item: T) => number | undefined): number | undefined;
contains<T>(this: T[], value: T): boolean;
count<T>(this: T[], predicate: (item: T) => boolean): number;
distinct<T>(this: T[]): T[];
empty<T>(this: T[]): boolean;
exists<T>(this: T[], predicate: (item: T) => boolean): boolean;
first<T>(this: T[], predicate?: ((item: T) => boolean)): T | undefined;
groupBy<T>(this: T[], keyGetter: (item: T) => number): {[index: number]: T[]};
groupBy<T>(this: T[], keyGetter: (item: T) => string): {[index: string]: T[]};
hasOneOf(this: T[], values: T[]): boolean;
insert<T>(this: T[], index: number, item: T): void;
intersect<T>(this: T[], other: T[]): T[];
last<T>(this: T[], predicate?: ((item: T) => boolean)): T | undefined;
min<T, V>(this: T[], selector: (item: T) => V): {value: V, index: number, item: T};
max<T, V>(this: T[], selector: (item: T) => V): {value: V, index: number, item: T};
none(this: boolean[]): boolean;
none<T>(this: T[], predicate: (item: T) => boolean): boolean;
orderBy<T, G extends number | string | Date>(this: T[], keyGetter: (item: T) => G | undefined, order?: SortOrder): T[];
orderByDescending<T, G extends number | string | Date>(this: T[], keyGetter: (item: T) => G | undefined): T[];
select<T, U>(this: T[], predicate: (item: T, index: number) => U): U[];
selectMany<TSource, TResult>(this: TSource[], selector: (item: TSource) => TResult[]): TResult[];
sequenceEqual<T>(this: T[], other: T[]): boolean;
single<T>(this: T[], predicate?: (item: T) => boolean): T | undefined;
skip(this: T[], count: number): T[];
sorted<T>(this: T[], order?: SortOrder): T[];
sum(this: number[]): number;
sum<T>(this: T[], callback: (item: T) => number | undefined): number;
take<T>(this: T[], count: number): T[];
union<T>(this: T[], other: T[]): void;
where<T>(this: T[], predicate: (item: T) => boolean): T[];
}
ArrayExtensions.ts:
///<reference path="ArrayExtensions.d.ts" />
Object.defineProperty(Array.prototype, 'first', {
value: function<T>(this: T[], predicate?: ((item: T) => boolean)): T | undefined {
let index = this.firstIndex(predicate);
return index != -1 ? this[index] : undefined;
}
});
index.ts:
import "extensions/ArrayExtensions";
The problem is we need to put these extensions in our shared library that we reuse in other projects. I can't find a way to export the TypeScript declarations and make other projects use them.
I have tried to put this in the index.ts
of the shared library:
export { Array } from "extensions/ArrayExtensions";
But it says the module has no exported member Array.
I have also tried to put the declarations directly into index.ts of the shared library instead of doing a reexport, but when importing it from the project that uses the library it says the module has no exported member Array. How do you export a declared interface of a project into another?
One problem is that you are thinking in terms of importing and exporting members of a module but what you actually want is a side effecting import, just like the one you have in the index file of the project that defines the additional members. This is because your extensions modify Global values and Global types, and don't export anything.
In other words, any project needing access to these members should import them like
import "extensions/ArrayExtensions";
You have additional problems however. You have a declaration file ArrayExtensions.d.ts
and a source file ArrayExtensions.ts
that are located side-by-side and the one references the other via
///<reference path="ArrayExtensions.d.ts" />
The number of a potential tooling problems this introduces, especially in a shared library, but even within a single project are so numerous that I will not enumerate them here. Please, please do not do this.
Put all of the code, declaration and implementation, in the .ts
file(s). And remove the ///<reference>
! you definitely neither want nor need anything of the sort. Anyone importing the implementation will inherently bring the corresponding type declarations into scope.
I do not know entirely how your projects reference one another, or what your build process is oh, so you may need to make a few additional changes, but what I have outlined above is important.