Я пишу библиотеку для реализации лениво оцененных запросов итерируемых типов в JavaScript. Я знаю, что уже есть доступные варианты для достижения этой цели, но у меня совершенно другой подход к раскрытию методов расширения.
Я испытываю затруднения при подходе к конкретной задаче проектирования, и мне было интересно, есть ли какой-нибудь обходной путь, о котором я не думал для решения проблемы.
Мое Enumerable<T>
определение класса и его интерфейс вместе с несколькими помощниками выглядит следующим образом:
// Iterator<T> defined in lib.es2015.iterable.d.ts
interface IteratorFunction<T> {
(this: IEnumerable<T> | void): Iterator<T>
}
interface CompareFunction<T> {
(a: T, b: T): number
}
// inspired by pattern for ArrayConstructor in lib.es5.d.ts
interface IEnumerableConstructor {
new <T>(iterator: IteratorFunction<T>): IEnumerable<T>
new <T>(iterator: IteratorFunction<T>, compare: null): IEnumerable<T>
new <T>(iterator: IteratorFunction<T>, compare: CompareFunction<T>): IOrderedEnumerable<T>
// static methods...
}
// Symbol.compare defined in separate file as a declaration merge to SymbolConstructor
interface IOrderedEnumerable<T> extends IEnumerable<T> {
readonly [Symbol.compare]: CompareFunction<T>
// overrides for thenBy()...
}
// IterableIterator<T> defined in lib.es2015.iterable.d.ts
interface IEnumerable<T> extends IterableIterator<T> {
// member methods...
}
class Enumerable<T> implements IEnumerableConstructor {
readonly [Symbol.iterator]: IteratorFunction<T>
readonly [Symbol.compare]: (null | CompareFunction<T>)
constructor (iterator: IteratorFunction<T>)
constructor (iterator: IteratorFunction<T>, compare: (null | CompareFunction<T>) = null) {
this[Symbol.iterator] = iterator
this[Symbol.compare] = compare
}
}
Проблема в том, что
constructor (iterator: IteratorFunction<T>)
относится к гипотетическому определению
new (iterator: IteratorFunction<T>): IEnumerable<T>
в отличие от предоставленного определения
new <T>(iterator: IteratorFunction<T>): IEnumerable<T>
и т. Д. Для других перегруженных объявлений в IEnumerable<T>
, сообщая мне об ошибке
Тип 'Enumerable<T>
' не соответствует сигнатуре 'new <T>(iterator: IteratorFunction<T>): IEnumerable<T>
'.
Я подумал, что изменение класса IEnumerableConstructor
также должно быть общим, но потом я столкнулся с проблемой, когда попытался сделать это:
declare global {
// ...
interface ArrayConstructor extends IEnumerableConstructor/*<T>*/ { } // illegal!
interface MapConstructor extends IEnumerableConstructor { }
interface SetConstructor extends IEnumerableConstructor { }
interface StringConstructor extends IEnumerableConstructor { }
interface TypedArrayConstructor extends IEnumerableConstructor { }
interface Array<T> extends IEnumerable<T> { }
interface Map<K, V> extends IEnumerable<[K, V]> { }
interface Set<T> extends IEnumerable<T> { }
interface String extends IEnumerable<string> { }
interface TypedArray extends IEnumerable<number> { }
}
Для пояснения, я объявил TypedArray
как класс, который Int8Array
и т. Д. Расширяется, согласно спецификации ECMAScript (но типизации для него не предоставлены в файлах TypeScript lib.*.d.ts
, поскольку он никогда не используется напрямую , что и понятно).
Как я уже сказал, эта реализация библиотеки представляет собой принципиально иной подход к предоставлению методов расширения встроенным в JavaScript, и я знаю обо всех подводных камнях, но сейчас я ищу способ предоставить определение для конструктора класса Enumerable<T>
, который учитывает универсальный тип IEnumerable<T>
. Есть идеи?