我正在编写一个库,以实现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> { }
}
为澄清起见,根据ECMAScript规范,我已经声明TypedArray
为Int8Array
扩展的类(但TypeScript lib.*.d.ts
中未提供其类型)文件,因为它从未被直接使用过,这是可以理解的。
正如我所说,此库实现是将扩展方法公开给JavaScript内置组件的一种截然不同的方法,我知道所有的陷阱,但现在我正在寻找一种方法来提供类Enumerable<T>
的构造函数的定义,该定义遵循IEnumerable<T>
的通用类型。有什么想法吗?
答案 0 :(得分:3)
IEnumerableConstructor
具有构造签名such interface can not be directly implemented by a class。
但是在TypeScript中,不需要将类明确声明为实现某些接口-毕竟,类型系统是结构化的,只要兼容该接口,就可以在需要该接口的地方使用该类。< / p>
据我在您的代码中所了解的,Enumerable<T>
实际上必须实现IEnumerable<T>
,因为这是声明interface IEnumerableConstructor
中的构造签名要产生的类型。因此,它应该具有next()
方法,然后,如果您只是省略implements IEnumerableConstructor
,它似乎就可以工作(但是如果将其替换为implements IEnumerable
,则可以使编译器检查该对象是否会受到损害)类正确实现了该接口):
class Enumerable<T> implements IEnumerable<T> {
readonly [Symbol.iterator]: IteratorFunction<T>
readonly compare: (null | CompareFunction<T>)
constructor (iterator: IteratorFunction<T>)
constructor (iterator: IteratorFunction<T>, compare?: (null | CompareFunction<T>)) {
this[Symbol.iterator] = iterator
this.compare = compare
}
next(): IteratorResult<T> {
return undefined;
}
}
const C: IEnumerableConstructor = Enumerable;
type A = { a: string };
let a: A[];
const c = new C(a.values); // inferred as const c: IEnumerable<A>